zoukankan      html  css  js  c++  java
  • 2020全国统一省选day2 作业题

    题目


    正解

    大套路题。
    看到之后是个人都知道要先反演一下推推式子:
    (为了方便表示,题目中的(w_{e_i})直接用(e_i)表示了)

    [sum_T (sum e_i)(gcd e_i) \ =sum_T (sum e_i)sum_{d|(gcd e_i)} phi(d) \ =sum_d phi(d) sum_{T,d|e_i}sum e_i]

    我们要求的是后面的那个东西。用人话说就是:所有边权为(d)的倍数的边,组成的生成树的边权和之和。
    然后很容易想到矩阵树。但是由于每个生成树的贡献是(sum e_i)而不是(prod e_i),所以要用到一个大套路:
    边权为(e_i)的边,丢到基尔霍夫矩阵中的边权为(1+e_ix)。矩阵树定理搞完之后求一次项系数即是答案。

    可以这么理解:对于某条边,如果计算它的贡献,就是要计算它的边权以及生成树包含这条边的方案数。

    计算的时候保留常数项和一次项即可。至于求逆,可以手算出(a+bx)的逆元为(frac{1}{a}-frac{b}{a^2}x)

    大优化:计算之前先判断一下符合条件的边是否能组成至少一个生成树。
    一个边权的因数个数最多为(144)。于是时间大概就是(O(frac{144mn^3}{n-1})=O(144n^4))
    显然实际上也不可能真正达到这个时间复杂度。所以是可以过的。


    代码

    using namespace std;
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cassert>
    #define N 35
    #define M N*N
    #define MX 152505
    #define mo 998244353
    #define ll long long
    ll qpow(ll x,ll y=mo-2){
    	ll r=1;
    	for (;y;y>>=1,x=x*x%mo)
    		if (y&1)
    			r=r*x%mo;
    	return r;
    }
    
    int n,m;
    struct edge{
    	int u,v,w;
    } ed[M];
    
    int mx,p[MX],np;
    bool inp[MX];
    int phi[MX];
    void getphi(int mx){
    	inp[1]=1,phi[1]=1;
    	for (int i=2;i<=mx;++i){
    		if (!inp[i]){
    			p[++np]=i;
    			phi[i]=i-1;
    		}
    		for (int j=1;j<=np && i*p[j]<=mx;++j){
    			inp[i*p[j]]=1;
    			if (i%p[j]==0){
    				phi[i*p[j]]=phi[i]*p[j];
    				break;
    			}
    			phi[i*p[j]]=phi[i]*(p[j]-1);
    		}
    	}
    }
    
    struct Po{
    	int x0,x1; 
    	bool eql0(){return x0==0 && x1==0;}
    	Po inv(){
    		int m=qpow(x0);
    		return (Po){m%mo,(ll)(mo-x1)*m%mo*m%mo};
    	}
    };
    Po operator-(Po a){return (Po){(mo-a.x0)%mo,(mo-a.x1)%mo};}
    Po operator+(Po a,Po b){return (Po){(a.x0+b.x0)%mo,(a.x1+b.x1)%mo};}
    Po operator-(Po a,Po b){return (Po){(a.x0-b.x0+mo)%mo,(a.x1-b.x1+mo)%mo};}
    Po operator*(Po a,Po b){return (Po){(ll)a.x0*b.x0%mo,((ll)a.x0*b.x1+(ll)a.x1*b.x0)%mo};}
    Po &operator+=(Po &a,Po b){return a=a+b;}
    Po &operator-=(Po &a,Po b){return a=a-b;}
    Po &operator*=(Po &a,Po b){return a=a*b;}
    int determinant(Po m[N][N]){
    	int o=1;
    	for (int i=1;i<n;++i){
    		int j=i;
    		for (;j<n && m[j][i].eql0();++j);
    		if (i!=j){
    			o=mo-o;
    			for (int k=i;k<n;++k)
    				swap(m[i][k],m[j][k]);
    		}
    		Po inv=-m[i][i].inv();
    		for (++j;j<n;++j)
    			if (!m[j][i].eql0()){
    				Po tmp=inv*m[j][i];
    				for (int k=i;k<n;++k)
    					m[j][k]+=m[i][k]*tmp;
    			}
    	}
    	Po r={o,0};
    	for (int i=1;i<n;++i)
    		r*=m[i][i];
    	return r.x1;
    }
    
    int dsu[N];
    int getdsu(int x){return dsu[x]==x?x:dsu[x]=getdsu(dsu[x]);}
    Po mat[N][N];
    int calc(int d){
    	for (int i=1;i<=n;++i)
    		dsu[i]=i;
    	for (int i=1;i<=m;++i)
    		if (ed[i].w%d==0){
    			int x=getdsu(ed[i].u),y=getdsu(ed[i].v);
    			if (x!=y)
    				dsu[x]=y;
    		}
    	getdsu(1);
    	for (int i=2;i<=n;++i)
    		if (getdsu(i)!=dsu[1])
    			return 0;
    	memset(mat,0,sizeof mat);
    	for (int i=1;i<=m;++i)
    		if (ed[i].w%d==0){
    			int u=ed[i].u,v=ed[i].v;
    			Po w={1,ed[i].w};
    			mat[u][u]+=w,mat[v][v]+=w;
    			mat[u][v]-=w,mat[v][u]-=w;
    		}
    	return determinant(mat);
    }
    int main(){
    	freopen("count.in","r",stdin);
    	freopen("count.out","w",stdout); 
    //	freopen("in.txt","r",stdin);
    //	freopen("out.txt","w",stdout);
    	scanf("%d%d",&n,&m);
    	for (int i=1;i<=m;++i){
    		scanf("%d%d%d",&ed[i].u,&ed[i].v,&ed[i].w);
    		mx=max(mx,ed[i].w);
    	}
    	getphi(mx);
    	ll ans=0;
    	for (int i=1;i<=mx;++i)	
    		ans+=(ll)phi[i]*calc(i)%mo;
    	ans%=mo;
    	printf("%lld
    ",ans);
    	return 0;
    }
    
    
  • 相关阅读:
    S1.2 Python开发规范指南
    time & datetime 模块
    10.27 sort
    basic play
    存储过程常规
    存储过程常规
    div学习之div中dl-dt-dd的详解
    div学习之div中dl-dt-dd的详解
    动态代理与静态代理的区别
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
  • 原文地址:https://www.cnblogs.com/jz-597/p/13195291.html
Copyright © 2011-2022 走看看