• [被踩计划] 题解 [省选联考 2020 A 卷] 作业题


    为什么叫被踩记录呢?因为感觉自己之前真的是太菜了,打算把之前联赛等考过的题目做一做,看看自已以前有多菜,所以取名叫被踩记录。

    题目链接

    题目分析

    [(sum_{i=1}^{n-1}w_{e_i}) imes gcd(w_{e_1},w_{e_2},dots,w_{e_{n-1}})= ]

    [(sum_{i=1}^{n-1}w_{e_i}) imes sum_{dmid w_{e_1},dmid w_{e_2},dots,dmid w_{e_{n-1}}}varphi(d)= ]

    [sum_{d}varphi(d)sum_{i=1}^{n-1}w_{e_i}[dmid w_{e_1}][dmid w_{e_2}]dots[dmid w_{e_{n-1}}] ]

    考虑枚举 (d) ,然后求里面的东西,也就是 (sum_{T}sum_{e_iin T} w_{e_i}) ,这个可以用矩阵树做,让第 (i) 条边边权为 (1+w_ix) ,那么最终一次项系数就是答案,为什么呢?发现我们实际上求的就是 (sum w_{e_i} imes sum_{T,e_iin T}) ,这个显然是没有问题。

    由于我们只要求一次项系数,所以可以在 (mod x^2) 意义下求解,乘法加法等很容易求,关键就是求逆元,设 (a+bx) 的逆元是 (Ax+B) ,那么有 ((Ax+B)(ax+b)equiv (Ab+Ba)x+Bbequiv 1 pmod {x^2}) ,于是 (Bequiv frac{1}{b},A=-frac{Ba}{b})

    注意到我们只需要枚举边数至少是 (n-1)(d) 就行了,这样的话复杂度大概是 (mathcal O(n^4 imes 144)) 的,具体我也不会证,可以看看这里

    参考代码

    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define ch() getchar()
    #define pc(x) putchar(x)
    using namespace std;
    template<typename T>void read(T&x){
    	static char c;static int f;
    	for(c=ch(),f=1;c<'0'||c>'9';c=ch())if(c=='-')f=-f;
    	for(x=0;c>='0'&&c<='9';c=ch())x=x*10+(c&15);x*=f;
    }
    template<typename T>void write(T x){
    	static char q[65];int cnt=0;
    	if(x<0)pc('-'),x=-x;
    	q[++cnt]=x%10,x/=10;
    	while(x)
    		q[++cnt]=x%10,x/=10;
    	while(cnt)pc(q[cnt--]+'0');
    }
    const int mod=998244353,maxn=35,maxw=160000,maxm=505;
    int mo(const int x){
    	return x>=mod?x-mod:x;
    }
    int power(int a,int x){
    	int re=1;
    	while(x){
    		if(x&1)re=1ll*re*a%mod;
    		a=1ll*a*a%mod,x>>=1;
    	}
    	return re;
    }
    struct Int{
    	int a,b;
    	Int(int a=0,int b=0):
    		a(a),b(b){}
    	Int operator + (const Int o)const{
    		return Int(mo(a+o.a),mo(b+o.b));
    	}
    	Int operator - (const Int o)const{
    		return Int(mo(mod-o.a+a),mo(mod-o.b+b));
    	}
    	Int operator * (const Int o)const{
    		return Int(1ll*a*o.a%mod,mo(1ll*a*o.b%mod+1ll*b*o.a%mod));
    	}
    	Int operator / (const Int o)const{
    		if(o.a==0)return Int(1ll*b*power(o.b,mod-2)%mod,0);		
    		int tmp=power(o.a,mod-2);
    		return Int(1ll*a*tmp%mod,1ll*tmp*tmp%mod*mo(mod-1ll*a*o.b%mod+1ll*b*o.a%mod)%mod);
    	}
    	Int operator += (const Int o){
    		return *this=*this+o;
    	}
    	Int operator -= (const Int o){
    		return *this=*this-o;
    	}
    	bool operator > (const Int o)const{
    		return a^o.a?a>o.a:b>o.b;
    	}
    };
    Int A[maxn][maxn];
    int solve(int n){
    	int re=0;
    	for(int i=1;i<n;++i){
    		int mx=i;
    		for(int j=i+1;j<n;++j)
    			if(A[j][i]>A[mx][i])
    				mx=j;
    		if(A[mx][i].a==0&&A[mx][i].b==0)
    			return 0;
    		if(mx!=i){
    			re^=1;
    			swap(A[mx],A[i]);
    		}
    		for(int j=1;j<n;++j){
    			if(i==j)continue;
    			Int tmp=A[j][i]/A[i][i];
    			for(int k=i;k<n;++k)
    				A[j][k]-=A[i][k]*tmp;
    		}
    	}
    	re=re?mod-1:1;
    	Int o=Int(1,0);
    	for(int i=1;i<n;++i)o=o*A[i][i];
    	return re=1ll*re*o.b%mod;
    }
    int cnt[maxw],S[maxm],T[maxm],W[maxm];
    int main(){
    	int n,m;read(n),read(m);
    	for(int i=1;i<=m;++i){
    		int u,v,w;
    		read(u),read(v),read(w);
    		int tmp=sqrt(w);
    		for(int j=1;j<=tmp;++j){
    			if(w%j==0){
    				++cnt[j];
    				if(j*j!=w)
    					++cnt[w/j];
    			}
    		}
    		S[i]=u,T[i]=v,W[i]=w;
    	}
    	int ans=0;
    	for(int i=1;i<=152501;++i){
    		if(cnt[i]<n-1)continue;
    		int tmp=sqrt(i),cp=i,phi=i;
    		for(int i=2;i<=tmp&&cp>1;++i){
    			if(cp%i==0){
    				phi=phi/i*(i-1);
    				while(cp%i==0)cp/=i;
    			}
    		}
    		if(cp>1)phi=phi/cp*(cp-1);
    		memset(A,0,sizeof A);
    		for(int j=1;j<=m;++j){
    			if(W[j]%i!=0)continue;
    			Int x=Int(1,W[j]);
    			A[S[j]][S[j]]+=x;
    			A[T[j]][T[j]]+=x;
    			A[S[j]][T[j]]-=x;
    			A[T[j]][S[j]]-=x;
    		}
    		ans=mo(ans+1ll*phi*solve(n)%mod);
    	}
    	write(ans),pc('
    ');
    	return 0;
    }
    
    
  • 相关阅读:
    C++入门经典-例5.19-指针的引用与传递参数
    C++入门经典-例5.18-通过引用交换数值
    C++入门经典-例5.17-右值引用的定义
    C++入门经典-例5.16-输出引用
    C++入门经典-例5.15-回收动态内存的一般处理步骤
    C++入门经典-例5.14-丢失的内存,关于内存泄漏
    C++入门经典-例5.13-内存安全,被销毁的内存
    C++入门经典-例5.12-动态内存的销毁
    C++入门经典-例5.11-动态分配空间,堆与栈
    C++入门经典-例5.10-指针作为返回值
  • 原文地址:https://www.cnblogs.com/lsq147/p/13751873.html
Copyright © 2020-2023  润新知