BZOJ 3601 一个人的数论(容斥+高斯消元/拉格朗日插值)

BZOJ 3601 一个人的数论(容斥+高斯消元/拉格朗日插值)

题意:求\(\sum _1^{n}[gcd(i,n)=1]i^d\)

其中\(n=\Pi_1^mp_i^{c_i}\)\(m\leq 1000,p_i,c_i\leq 10^9\)

???丧心病狂???

我们采取容斥来计算,但是首先要把这个\(i^d\)求和搞定

由于神奇的数学归纳法,我们知道,\(F(n)=\sum_{i=1}^ni^d\)可以用一个\(d+1\)次的多项式表示

即$F(n)=\sum _{i=1}^{d+1}w_i \cdot n^i $

带入\(d+1\)个值,求出\(w_i\),当然我们可以高斯消元/拉格朗日插值

// 暴力高斯消元
namespace Gauss{
	ll a[111][111];
	void Solve() {
		ll tmp=0;
		rep(i,0,d) {
			rep(j,0,d) a[i][j]=qpow(i+1,j+1);
			tmp=(tmp+qpow(i+1,d))%P;
			a[i][d+1]=tmp; // 预处理点值式
		}
		rep(i,0,d) {
			rep(j,i,d) if(a[j][i]) {
				swap(a[i],a[j]);
				break;
			}
			if(!a[i][i]) continue;
			ll Inv=qpow(a[i][i],P-2);
			rep(j,i+1,d) {
				ll t=a[j][i]*Inv%P;
				rep(k,i,d+1) a[j][k]=(a[j][k]-a[i][k]*t%P+P)%P;
			}
		}
		drep(i,d,0) {
			w[i+1]=a[i][d+1]*qpow(a[i][i],P-2)%P;
			rep(j,0,i-1) a[j][d+1]=(a[j][d+1]-a[j][i]*w[i+1]%P+P)%P;
		}
	}
}

考虑\(2^m\)枚举容斥,考虑枚举当前的数包含的因子集合为\(S\),答案就是

\[\sum _{S\in p} (-1)^{|S|}\sum_{i=1}^{\frac{n}{\Pi S_j}} (i \Pi S_j)^d \]

\[=\sum _{S\in p} (-1)^{|S|}(\Pi S_j)^d F(\frac{n}{\Pi S_j}) \]

n=1,d=rd(),m=rd();	
rep(i,1,m) {
	a[i]=rd(),b[i]=rd();
	n=1ll*n*qpow(a[i],b[i])%P;
}
Gauss::Solve();

rep(i,0,(1<<m)-1) {
	ll t=1,res=0,c=0;
	rep(j,1,m) if(i&(1<<(j-1))) t=t*a[j]%P,c^=1;
	ll x=n*qpow(t,P-2)%P;
	rep(j,1,d+1) res=(res+qpow(x,j)*w[j])%P;
	res=res*qpow(t,d)%P;
	if(c) ans=(ans-res)%P;
	else ans=(ans+res)%P;
}
ans=(ans%P+P)%P;
printf("%lld\n",ans),ans=0;

考虑\(F(n)\)的每一项\(w_in^i\)对于答案的贡献

\[\sum _{S\in p} (-1)^{|S|}(\Pi S_j)^d w_i(\frac{n}{\Pi S_j})^i \]

这个值可以压进转移中直接完成计算

rep(i,1,d+1) {
	dp[0]=1;
	rep(j,1,m) {
		dp[j]=dp[j-1]*qpow(qpow(a[j],b[j]),i)%P; //不选这个因数
		dp[j]=(dp[j]-dp[j-1]*qpow(qpow(a[j],b[j]-1),i)%P*qpow(a[j],d))%P;// 选这个因数,系数取反
	}
	ans=(ans+dp[m]*w[i])%P; // 对于每个wi统计答案
}

posted @ 2020-04-22 22:31  chasedeath  阅读(185)  评论(0编辑  收藏  举报