【联合省选 2020 A】题解

冰火战士

线段树上二分即可
具体实现可以参见代码

#include<bits/stdc++.h>
using namespace std;
#define cs const
#define pb push_back
#define pii pair<int,int>
#define fi first
#define se second
#define ll long long
#define bg begin
namespace IO{

cs int rlen=1<<22|1;
char ibuf[rlen],*ib,*ob;
inline char gc(){
	(ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,rlen,stdin));
	return (ib==ob)?EOF:*ib++;
}
inline int read(){
	char ch=gc();
	int res=0;bool f=0;
	while(!isdigit(ch))f=ch=='-',ch=gc();
	while(isdigit(ch))res=(res*10)+(ch^48),ch=gc();
	return f?-res:res;
}
char obuf[(int)(5e7+7)],*oh=obuf,ch[23];
template<typename T>void write(T a,char c){
	if(a<0)*oh++='-',a=-a;int tl=0;
	do ch[++tl]=a%10;while(a/=10);
	while(tl)*oh++=ch[tl--]^48;*oh++=c; 
}
void writes(char T[],char c){
	for(int i=0;T[i]!='\0';i++)*oh++=T[i];
	*oh++=c;
}
struct obuf_flusher{~obuf_flusher(){fwrite(obuf,1,oh-obuf,stdout);}}Flusher;

}
using IO::read;
using IO::write;
using IO::writes;
template<typename tp>inline void chemx(tp &a,tp b){(a<b)?(a=b):0;}
template<typename tp>inline void chemn(tp &a,tp b){(a>b)?(a=b):0;}

cs int N=2e6+5;
int n,m,a[N],b[N],fr[N],pf[N];
namespace seg{

cs int N=::N<<2;
int sa[N],sb[N],fir[N];
#define lc (u<<1)
#define rc ((u<<1)|1)
int p,kd,k;
void upd(int u,int l,int r){
	if(l==r){
		if(!kd)sa[u]+=k;
		else sb[u]+=k;
		fir[u]=sb[u]?l:-1;
		return;
	}int mid=(l+r)>>1;
	if(p<=mid)upd(lc,l,mid);
	else upd(rc,mid+1,r);
	sa[u]=sa[lc]+sa[rc],sb[u]=sb[lc]+sb[rc];
	fir[u]=sb[lc]?fir[lc]:fir[rc];
}
void update(int _p,int _kd,int _k){
	p=_p,kd=_kd,k=_k,upd(1,1,n);
}
pii query(int u,int l,int r,int _sa,int _sb){
	if(l==r)return pii(l,2*min(_sa+sa[u],_sb+sb[u]));
	int mid=(l+r)>>1,ls=_sa+sa[lc],rs=_sb+sb[rc];
	if(_sa+sa[lc]<=_sb+sb[rc])return query(rc,mid+1,r,ls,_sb);
	else {
		pii x=query(lc,l,mid,_sa,rs);
		if(x.se==2*min(ls,rs))x.fi=fir[rc];
		return x;
	}
}
#undef lc
#undef mid
}
struct opt{int kd,x,y;}p[N];
int lower(int x){
	int l=1,r=n,res=n;
	while(l<=r){
		int mid=(l+r)>>1;
		if(b[mid]>=x)res=mid,r=mid-1;
		else l=mid+1;
	}return res;
}
int main(){
	#ifdef Stargazer
	freopen("lx.in","r",stdin);
	freopen("my.out","w",stdout);
	#endif
	m=read();
	for(int i=1;i<=m;i++){
		int op=read();
		if(op==1){
			p[i].kd=read(),p[i].x=read(),p[i].y=read();
			b[++n]=p[i].x;
		}
		else fr[i]=read(),p[i]=p[fr[i]],p[i].y=-p[i].y;
	}sort(b+1,b+n+1);
	n=unique(b+1,b+n+1)-b-1;
	for(int i=1;i<=m;i++){
		int ps;
		if(p[i].y>=0)ps=lower(p[i].x);
		else ps=pf[fr[i]];pf[i]=ps;
		seg::update(ps,p[i].kd,p[i].y);
		pii x=seg::query(1,1,n,0,0);
		if(!x.se)writes("Peace",'\n');
		else write(b[x.fi],' '),write(x.se,'\n');
	}return 0;
}

组合数问题

直接斯特林展开然后二项式定理合并组合数即可
如果转成下降幂多项式做可以两个log,如果利用组合意义/推导可以一个log

#include<bits/stdc++.h>
using namespace std;
#define cs const
#define pb push_back
#define pii pair<int,int>
#define fi first
#define se second
#define ll long long
#define bg begin
namespace IO{

cs int rlen=1<<22|1;
char ibuf[rlen],*ib,*ob;
inline char gc(){
	(ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,rlen,stdin));
	return (ib==ob)?EOF:*ib++;
}
inline int read(){
	char ch=gc();
	int res=0;bool f=0;
	while(!isdigit(ch))f=ch=='-',ch=gc();
	while(isdigit(ch))res=(res*10)+(ch^48),ch=gc();
	return f?-res:res;
}
}

using IO::read;
template<typename tp>inline void chemx(tp &a,tp b){(a<b)?(a=b):0;}
template<typename tp>inline void chemn(tp &a,tp b){(a>b)?(a=b):0;}

int mod;
inline int add(int a,int b){return a+b>=mod?a+b-mod:a+b;}
inline int dec(int a,int b){return a<b?a-b+mod:a-b;}
inline int mul(int a,int b){return (ll)a*b%mod;}
inline void Add(int &a,int b){a=a+b>=mod?a+b-mod:a+b;}
inline void Dec(int &a,int b){a=a<b?a-b+mod:a-b;}
inline void Mul(int &a,int b){a=(ll)a*b%mod;}
inline int ksm(int a,int b,int res=1){for(;b;b>>=1,Mul(a,a))if(b&1)Mul(res,a);return res;}
inline int Inv(int x){return ksm(x,mod-2);}
cs int N=1005;
int n,x,m,a[N],s[N][N];
int main(){
	#ifdef Stargazer
	freopen("lx.in","r",stdin);
	#endif
	n=read(),x=read(),mod=read(),m=read();
	s[0][0]=1;
	for(int i=0;i<=m;i++)a[i]=read();
	for(int i=1;i<=m;i++)
	for(int j=1;j<=i;j++)s[i][j]=add(s[i-1][j-1],mul(s[i-1][j],j));
	int res=0;
	for(int t=0,mtx=1,dn=1;t<=m;Mul(dn,n-t),Mul(mtx,x),t++){
		int nw=0;
		for(int j=t;j<=m;j++)Add(nw,mul(a[j],s[j][t]));
		Add(res,mul(nw,mul(dn,mul(mtx,ksm(add(1,x),n-t)))));
	}cout<<res;return 0;
}

魔法商店

首先可以利用拟阵推出偏序关系
其实就是不同元素在满秩线性基中的相互替换
然后就变成 L 2 L_2 L2保序回归问题了
由于是整数,直接整数整体二分然后最小割 c h e c k check check即可

#include<bits/stdc++.h>
using namespace std;
#define cs const
#define pb push_back
#define pii pair<int,int>
#define fi first
#define se second
#define ll long long
#define bg begin
typedef unsigned long long ul;
namespace IO{

cs int rlen=1<<22|1;
char ibuf[rlen],*ib,*ob;
inline char gc(){
	(ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,rlen,stdin));
	return (ib==ob)?EOF:*ib++;
}
inline int read(){
	char ch=gc();
	int res=0;bool f=0;
	while(!isdigit(ch))f=ch=='-',ch=gc();
	while(isdigit(ch))res=(res*10)+(ch^48),ch=gc();
	return f?-res:res;
}
inline ul readul(){
	char ch=gc();
	ul res=0;
	while(!isdigit(ch))ch=gc();
	while(isdigit(ch))res=(res*10)+(ch^48),ch=gc();
	return res;
}

}

using IO::read;
using IO::readul;
template<typename tp>inline void chemx(tp &a,tp b){(a<b)?(a=b):0;}
template<typename tp>inline void chemn(tp &a,tp b){(a>b)?(a=b):0;}

cs int N=1055,M=66,inf=1e9;
int S,T,tot;
bool vis[N];
namespace flow{

struct edge{
	int v,cap,r;
	edge(int _v=0,int _c=0,int _r=0):v(_v),cap(_c),r(_r){}
};
vector<edge>e[N];
typedef vector<edge>::iterator It;
It tp[N];int lev[N];
inline void addedge(int u,int v,int cap){
	e[u].pb(edge(v,cap,e[v].size()));
	e[v].pb(edge(u,0,e[u].size()-1));
}
void clearflow(){
	for(int i=1;i<=tot;i++)e[i].clear();
	memset(vis,0,sizeof(bool)*(tot+1));
	tot=0;
}
bool bfs(){
	memset(lev,-1,sizeof(int)*(tot+1));
	queue<int> q;lev[S]=0,q.push(S);
	while(q.size()){
		int u=q.front();q.pop();
		for(cs edge &x:e[u])if(lev[x.v]==-1&&x.cap>0){
			lev[x.v]=lev[u]+1,q.push(x.v);
		}
	}return lev[T]!=-1;
}
int dfs(int u,int flow){
	if(u==T||!flow)return flow;
	int res=0;
	for(It &it=tp[u];it!=e[u].end();++it){
		if(lev[it->v]==lev[u]+1&&it->cap>0){
			int now=dfs(it->v,min(it->cap,flow-res));
			res+=now,it->cap-=now,e[it->v][it->r].cap+=now;
			if(flow==res)break;
		}
	}return res;
}
inline void dinic(){
	while(bfs()){
		for(int i=1;i<=tot;i++)tp[i]=e[i].bg();
		dfs(S,inf);
	}
}
void color(int u){
	vis[u]=1;
	for(cs edge &x:e[u])if(x.cap>0&&!vis[x.v])color(x.v);
}

}
using flow::addedge;
using flow::dinic;
using flow::color;
using flow::clearflow;

namespace Bas{

ul b[M];
void clearbas(){memset(b,0,sizeof(b));}
void insert(ul x){
	for(int i=63;~i;i--)if((x>>i)&1){
		if(b[i])x^=b[i];
		else{b[i]=x;break;}
	}
}
bool check(ul x){
	for(int i=63;~i;i--)if((x>>i)&1)x^=b[i];
	return (!!x);
}

}
using Bas::clearbas;
using Bas::insert;
using Bas::check;
int n,m,p[N],v[N],a[M],b[M],inst[N];
ul c[N];
vector<int> lk[N];
ll ans;
ll P(int x){return (ll)x*x;}
void solve(int l,int r,int ql,int qr){
	if(l>r)return;
	if(ql==qr){
		for(int i=l;i<=r;i++)ans+=P(v[p[i]]-ql);
		return;
	}
	int mid=(ql+qr)>>1;
	clearflow(),tot=r-l+1,S=++tot,T=++tot;
	for(int i=l;i<=r;i++)inst[p[i]]=i-l+1;
	for(int t=l,i;t<=r;t++){
		i=p[t];int vl=2*(v[i]-mid)-1;
		if(vl>0)addedge(inst[i],T,vl);
		else addedge(S,inst[i],-vl);
//		if(v[i]>mid)addedge(inst[i],T,P(v[i]-mid)-P(v[i]-mid-1));
//		else addedge(S,inst[i],P(mid+1-v[i])-P(mid-v[i]));
		for(int v:lk[i])if(inst[v])addedge(inst[i],inst[v],inf);
	}
	for(int i=l;i<=r;i++)inst[p[i]]=0;
	dinic(),color(S);int ps=l;
	for(int i=l;i<=r;i++)
	if(vis[i-l+1])swap(p[i],p[ps++]);
	solve(l,ps-1,ql,mid),solve(ps,r,mid+1,qr);
}
int main(){
	#ifdef Stargazer
	freopen("lx.in","r",stdin);
	#endif
	n=read(),m=read();
	for(int i=1;i<=n;i++)c[i]=readul();
	for(int i=1;i<=n;i++)v[i]=read();
	for(int i=1;i<=m;i++)a[i]=read();
	for(int i=1;i<=m;i++)b[i]=read();
	for(int i=1;i<=m;i++)inst[a[i]]=1;
	for(int i=1;i<=m;i++){
		clearbas();
		for(int j=1;j<=m;j++)if(i^j)insert(c[a[j]]);
		for(int j=1;j<=n;j++)if(!inst[j]&&check(c[j]))lk[j].pb(a[i]);
		//,cout<<j<<" "<<a[i]<<'\n';
	}
//	cout<<'\n';
	for(int i=1;i<=m;i++)inst[a[i]]=0;
	for(int i=1;i<=m;i++)inst[b[i]]=1;
	for(int i=1;i<=m;i++){
		clearbas();
		for(int j=1;j<=m;j++)if(i^j)insert(c[b[j]]);
		for(int j=1;j<=n;j++)if(!inst[j]&&check(c[j]))lk[b[i]].pb(j);
		//,cout<<b[i]<<" "<<j<<'\n';
	}
	for(int i=1;i<=m;i++)inst[b[i]]=0;
	for(int i=1;i<=n;i++)p[i]=i;
	solve(1,n,0,1e6);
	cout<<ans<<'\n';
	return 0;
}

信号传递

状压 d p dp dp,预处理贡献卡空间,分块一下即可

#include<bits/stdc++.h>
using namespace std;
#define cs const
#define pb push_back
#define pii pair<int,int>
#define fi first
#define se second
#define ll long long
#define bg begin
namespace IO{

cs int rlen=1<<22|1;
char ibuf[rlen],*ib,*ob;
inline char gc(){
	(ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,rlen,stdin));
	return (ib==ob)?EOF:*ib++;
}
inline int read(){
	char ch=gc();
	int res=0;bool f=0;
	while(!isdigit(ch))f=ch=='-',ch=gc();
	while(isdigit(ch))res=(res*10)+(ch^48),ch=gc();
	return f?-res:res;
}

}

using IO::read;
template<typename tp>inline void chemx(tp &a,tp b){(a<b)?(a=b):0;}
template<typename tp>inline void chemn(tp &a,tp b){(a>b)?(a=b):0;}

cs int N=24,M=(1<<23)|5,B=(1<<12)|5;
int lk[N][N],coef11[N][B],coef12[N][B],coef21[N][B],coef22[N][B];
int ls,n,vk,str[100005],lim,lm1,lm2,ln1,ln2;
int f[M],ct[M],cnt[M];
inline int coef1(int i,int s){
	return coef11[i][s&(lm1-1)]+coef12[i][(s>>12)&(lm2-1)];
}
inline int coef2(int i,int s){
	return coef21[i][s&(lm1-1)]+coef22[i][(s>>12)&(lm2-1)];
}
#define lb(x) (x&(-x))
int main(){
	#ifdef Stargazer
	freopen("lx.in","r",stdin);
	#endif
	ls=read(),n=read(),vk=read(),lim=1<<n;
	ln1=min(n,12),ln2=n-ln1;
	lm1=1<<ln1,lm2=1<<ln2;
	for(int i=1;i<=n;i++)ct[1<<(i-1)]=i;
	for(int i=0;i<lim;i++)cnt[i]=cnt[i>>1]+(i&1);
	for(int i=1;i<=ls;i++)
		str[i]=read();
	for(int i=1;i<ls;i++)
		lk[str[i]][str[i+1]]++;
	for(int i=1;i<=n;i++){
		for(int s=0;s<lm1;s++)
		for(int j=1;j<=ln1;j++)if(s&(1<<(j-1))){
			coef11[i][s]+=lk[i][j]*vk+lk[j][i];
			coef21[i][s]+=lk[j][i]*vk-lk[i][j];
		}
		for(int s=0;s<lm2;s++)
		for(int j=1;j<=ln2;j++)if(s&(1<<(j-1))){
			coef12[i][s]+=lk[i][j+ln1]*vk+lk[j+ln1][i];
			coef22[i][s]+=lk[j+ln1][i]*vk-lk[i][j+ln1];
		}
	}memset(f,127/2,sizeof(f));
	f[0]=0;
	for(int s=1;s<lim;s++){
		int &res=f[s];
		for(int t=s,i=ct[lb(t)];t;t-=lb(t),i=ct[lb(t)]){
			chemn(res,f[s-(1<<(i-1))]+(coef1(i,s-(1<<(i-1)))+coef2(i,(lim-1)^s))*cnt[s]);
		}
	}cout<<f[lim-1]<<'\n';
	return 0;
}

直接 0 / 1 t r i e 0/1trie 0/1trie合并维护子树答案,+1用之前agc的套路低位到高位维护,直接 s h i f t shift shift即可

另一种做法是
考虑每个点每一位对祖先有贡献的是一段一段的,在倍增数组上差分贡献最后统计答案也可以做到 O ( n l o g n ) O(nlogn) O(nlogn)

#include<bits/stdc++.h>
using namespace std;
#define cs const
#define pb push_back
#define pii pair<int,int>
#define fi first
#define se second
#define ll long long
#define bg begin
namespace IO{

cs int rlen=1<<22|1;
char ibuf[rlen],*ib,*ob;
inline char gc(){
	(ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,rlen,stdin));
	return (ib==ob)?EOF:*ib++;
}
inline int read(){
	char ch=gc();
	int res=0;bool f=0;
	while(!isdigit(ch))f=ch=='-',ch=gc();
	while(isdigit(ch))res=(res*10)+(ch^48),ch=gc();
	return f?-res:res;
}

}

using IO::read;
template<typename tp>inline void chemx(tp &a,tp b){(a<b)?(a=b):0;}
template<typename tp>inline void chemn(tp &a,tp b){(a>b)?(a=b):0;}
char xx;
cs int N=525015;
namespace trie{

cs int N=::N*20;
int lc[N],rc[N],xo[N],sm[N],tot;
bool sz[N];
void pushnow(int u,int dep,int k){
	xo[u]^=k;if(k&(1<<dep))swap(lc[u],rc[u]);
}
void pushdown(int u,int dep){
	if(!xo[u])return;
	pushnow(lc[u],dep+1,xo[u]);
	pushnow(rc[u],dep+1,xo[u]);
	xo[u]=0;
}
void merge(int &u,int r1,int r2,int dep){
	if(!r1||!r2){u=r1+r2;return;}
	pushdown(r1,dep),pushdown(r2,dep);
	u=r1,sz[u]=sz[r1]^sz[r2];
	merge(lc[u],lc[r1],lc[r2],dep+1);
	merge(rc[u],rc[r1],rc[r2],dep+1);
	sm[u]=(sm[lc[u]]^sm[rc[u]])+(1<<dep)*sz[rc[u]];
}
void insert(int &u,int k,int dep){
	if(!u)u=++tot;sz[u]^=1;if(dep==21)return;
	if(!((k>>dep)&1))insert(lc[u],k,dep+1);
	else insert(rc[u],k,dep+1);
	sm[u]=(sm[lc[u]]^sm[rc[u]])+(1<<dep)*sz[rc[u]];
}
void shift(int u,int dep){
	if(!u)return;
	pushdown(u,dep);
	swap(lc[u],rc[u]);
	shift(lc[u],dep+1);
	sm[u]=(sm[lc[u]]^sm[rc[u]])+(1<<dep)*sz[rc[u]];
}

}
using trie::insert;
using trie::merge;
using trie::pushnow;
using trie::shift;
using trie::sm;
char yy;
int rt[N],n,val[N];
ll ans;
vector<int> e[N];
void dfs(int u){
	for(int v:e[u]){
		dfs(v);
		merge(rt[u],rt[u],rt[v],0);
	}
	shift(rt[u],0);
	insert(rt[u],val[u],0);
	ans+=sm[rt[u]];
//	cout<<u<<" "<<ans<<'\n';
//	if(u==2)exit(0);
}
int main(){
	#ifdef Stargazer
	freopen("lx.in","r",stdin);
	#endif
	n=read();
	for(int i=1;i<=n;i++)val[i]=read();
	for(int i=2;i<=n;i++)e[read()].pb(i);
	dfs(1);
	cout<<ans<<'\n';
	return 0;
}

作业题

被玩烂的套路
枚举每个权值把倍数的边提出来矩阵树,最后容斥回答案
矩阵树如果对占位多项式插值是 O ( n 4 ) O(n^4) O(n4)
如果用二项式定理做,即每个是 1 + w x 1+wx 1+wx % x 2 \%x^2 %x2下直接求多项式即可单次 O ( n 3 ) O(n^3) O(n3)

#include<bits/stdc++.h>
using namespace std;
#define cs const
#define pb push_back
#define pii pair<int,int>
#define fi first
#define se second
#define ll long long
#define bg begin
namespace IO{

cs int rlen=1<<22|1;
char ibuf[rlen],*ib,*ob;
inline char gc(){
	(ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,rlen,stdin));
	return (ib==ob)?EOF:*ib++;
}
inline int read(){
	char ch=gc();
	int res=0;bool f=0;
	while(!isdigit(ch))f=ch=='-',ch=gc();
	while(isdigit(ch))res=(res*10)+(ch^48),ch=gc();
	return f?-res:res;
}

}

using IO::read;
template<typename tp>inline void chemx(tp &a,tp b){(a<b)?(a=b):0;}
template<typename tp>inline void chemn(tp &a,tp b){(a>b)?(a=b):0;}

cs int N=34,M=152511;
cs int mod=998244353;
inline int add(int a,int b){return a+b-(mod&-(a+b>=mod));}
inline int dec(int a,int b){return a-b+(mod&-(a<b));}
inline int mul(int a,int b){static ll r;r=(ll)a*b;return r>=mod?r%mod:r;}
inline void Add(int &a,int b){a=a+b>=mod?a+b-mod:a+b;}
inline void Dec(int &a,int b){a=a<b?a-b+mod:a-b;}
inline void Mul(int &a,int b){a=(ll)a*b%mod;}
inline int ksm(int a,int b,int res=1){for(;b;b>>=1,Mul(a,a))if(b&1)Mul(res,a);return res;}
inline void ex_gcd(int a,int b,int &x,int &y){
	if(!b){x=1,y=0;return;}ex_gcd(b,a%b,y,x);y-=a/b*x;
}
inline int Inv(int a){
	int x,y;ex_gcd(mod,a,y,x);
	return x+(x>>31&mod);
}
int gcd(int a,int b){
	return b?gcd(b,a%b):a;
}
bool vis[M];
int pri[M],pcnt,lim;
inline void init_sieve(cs int n){
	for(int i=2;i<=n;i++){
		if(!vis[i])pri[++pcnt]=i;
		for(int j=1;j<=pcnt&&i*pri[j]<=n;j++){
			vis[i*pri[j]]=1;
			if(i%pri[j]==0)break;
		}
	}
}
inline void fgt(int *f){
	for(int i=1;i<=pcnt;i++)
	for(int j=1,l=lim/pri[i];j<=l;j++)Dec(f[j],f[j*pri[i]]);
}
struct node{
	int a,b;
	node(int _a=0,int _b=0):a(_a),b(_b){}
	bool is_z()cs{return !a&&!b;}
	friend inline node operator +(cs node &a,cs node &b){
		return node(add(a.a,b.a),add(a.b,b.b));
	}
	friend inline node operator -(cs node &a,cs node &b){
		return node(dec(a.a,b.a),dec(a.b,b.b));
	}
	friend inline node operator *(cs node &a,cs int &b){
		return node(mul(a.a,b),mul(a.b,b));
	}
	friend inline node operator *(cs node &a,cs node &b){
		return node(mul(a.a,b.a),add(mul(a.b,b.a),mul(a.a,b.b)));
	}
	void operator +=(cs node &b){*this=*this+b;}
	void operator -=(cs node &b){*this=*this-b;}
};
node Inv(node x){
	if(!x.b)return node(Inv(x.a),0);
	int c=Inv(x.a),d=dec(0,mul(x.b,mul(c,c)));
	return node(c,d);
}
node a[N][N];
int u[N*N],v[N*N],w[N*N];
int n,m,f[M];
int pr[N],cnt[N],tot;
vector<int> eid[M];
void dfs(int ps,int mt,int id){
	if(ps>tot)return eid[mt].pb(id);
	for(int i=0;i<=cnt[ps];i++){
		dfs(ps+1,mt,id),mt*=pr[ps];
	}
}
void divid(int k,int id){tot=0;int x=k;
	for(int i=2;i*i<=x;i++)if(x%i==0){
		pr[++tot]=i;cnt[tot]=0;
		while(x%i==0)cnt[tot]++,x/=i;
	}if(x>1)pr[++tot]=x,cnt[tot]=1;
	dfs(1,1,id);
}
int fa[N];
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
void merge(int u,int v){
	u=find(u),v=find(v);
	if(u==v)return;
	fa[u]=v;
}
inline int Det(int n){
	node res(1,0);
	for(int i=1;i<=n;i++){
		int ps=i;
		for(;ps<=n;ps++)if(!a[ps][i].is_z()){ps=i;break;}
		if(ps!=i)swap(a[ps],a[i]),res=node()-res;
		node iv=Inv(a[i][i]);res=res*a[i][i];
		for(int j=i+1;j<=n;j++){
			node mt=a[j][i]*iv;
			for(int k=i;k<=n;k++)
			a[j][k]-=a[i][k]*mt;
		}
	}return res.b;
}
inline void solve(int k){
	int vl=0;
	for(int i=1;i<=n;i++)fa[i]=i;
	for(int i:eid[k])merge(u[i],v[i]),vl=gcd(vl,w[i]);
	for(int i=1;i<=n;i++)if(find(i)!=find(1))return;
	if(vl!=k)return;
	for(int i=1;i<=n;i++)
	for(int j=1;j<=n;j++)a[i][j]=node(0,0);
	for(int i:eid[k]){
		node vl(1,w[i]);
		a[u[i]][u[i]]+=vl,a[v[i]][v[i]]+=vl;
		a[u[i]][v[i]]-=vl,a[v[i]][u[i]]-=vl;
	}
	f[k]=Det(n-1);
	for(int i=k+k;i<=lim;i+=k)Dec(f[k],f[i]);
}
int main(){
	#ifdef Stargazer
	freopen("lx.in","r",stdin);
	#endif
	n=read(),m=read();
	for(int i=1;i<=m;i++){
		u[i]=read(),v[i]=read(),w[i]=read();
		divid(w[i],i),chemx(lim,w[i]);
	}init_sieve(lim);
	for(int i=lim;i;i--)if(eid[i].size()>=n-1)solve(i);
	int res=0;
	for(int i=1;i<=lim;i++)Add(res,mul(f[i],i));
	cout<<res<<'\n';return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值