【BZOJ 3601】一个人的数论

题目

(sum_{i=1}^n[(i,n)=1]i^m)(n)非常大,以质因数分解后的形式给出。

随手反演一波,上面那个式子就是

[sum_{d|n}mu(d)sum_{i=1}^{frac{n}{d}}(i imes d)^m=sum_{d|n}mu(d)d^msum_{i=1}^{frac{n}{d}}i^m ]

我们发现这有一个自然数幂次方和,众所周知这是一个(m+1)多项式,我们可以把系数插出来,之后变成了

[sum_{d|n}mu(d)d^msum_{i=0}^{m+1}f_i(frac{n}{d})^i=sum_{i=0}^{m+1}f_isum_{d|n}mu(d)d^m(frac{n}{d})^i ]

不妨设(g(n,i)=sum_{d|n}mu(d)d^m(frac{n}{d})^i=n^isum_{d|n}mu(d)d^{m-i}),这显然是一个积性函数;于是每个质因子是独立的,正好给出了(n)的分解式,于是算一下每个质数次幂的值就好了;

对于(g(p^a,i))只有(mu(1),mu(p))不是0,于是单独算一下这两项就好了

代码

#include<bits/stdc++.h>
#define re register
#define LL long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
const int mod=1e9+7;
inline int dqm(int x) {return x<0?x+mod:x;}
inline int qm(int x) {return x>=mod?x-mod:x;}
inline int ksm(int a,int b) {
	int s=1;for(;b;b>>=1,a=1ll*a*a%mod)if(b&1)s=1ll*s*a%mod;return s;
}
const int maxn=1005;
int n,m,p[maxn],w[maxn],pre[maxn];
int f[maxn],g[maxn],h[maxn],ifac[maxn],fac[maxn];
inline void Lagrange(int N) {
	for(re int i=1;i<=N;i++)pre[i]=qm(pre[i-1]+ksm(i,m));
	fac[0]=ifac[0]=g[0]=1;
	for(re int i=1;i<=N;i++)fac[i]=1ll*fac[i-1]*i%mod;
	ifac[N]=ksm(fac[N],mod-2);
	for(re int i=N-1;i;--i)ifac[i]=1ll*ifac[i+1]*(i+1)%mod;
	for(re int i=0;i<=N;++i) 
		for(re int j=i+1;j>=0;j--) {
			g[j]=1ll*g[j]*dqm(-i)%mod;
			if(j)g[j]=qm(g[j]+g[j-1]);
		}
	for(re int i=1;i<=N;i++) {
		int v=1ll*pre[i]*ifac[i]%mod*ifac[N-i]%mod*((N-i)&1?mod-1:1)%mod;
		int Inv=ksm(dqm(-i),mod-2);h[0]=1ll*g[0]*Inv%mod;
		for(re int j=1;j<=N;j++)h[j]=1ll*dqm(g[j]-h[j-1])*Inv%mod;
		for(re int j=0;j<=N;j++)f[j]=qm(f[j]+1ll*v*h[j]%mod);
	}
}
int main() {
	scanf("%d%d",&m,&n);Lagrange(m+1);int ans=0;
	for(re int i=1;i<=n;i++)scanf("%d%d",&p[i],&w[i]);
	for(re int i=1;i<=m+1;i++) {
		int prod=1;
		for(re int j=1;j<=n;j++) {
			int nw=ksm(p[j],1ll*w[j]*i%(mod-1));
			int u=(m-i+mod-1)%(mod-1);
			prod=1ll*prod*nw%mod*dqm(1-ksm(p[j],u))%mod;
		}
		ans=qm(ans+1ll*f[i]*prod%mod);
	}
	printf("%d
",ans);
	return 0;
}
原文地址:https://www.cnblogs.com/asuldb/p/12264116.html