BZOJ 3601 一个人的数论

第一次被搞。在这里插入图片描述在这里插入图片描述在这里插入图片描述
在这里插入图片描述
这个套路深啊。。。。。。
∑ i = 1 n − 1 [ gcd ⁡ ( i , n ) = = 1 ] i d = ∑ i = 1 n ∑ p ∣ i , p ∣ n μ ( p ) i d = ∑ p ∣ n n μ ( p ) ∑ i = 1 n p ( i p ) d = ∑ p ∣ n n μ ( p ) p d ∑ i = 1 n p i d \sum_{i=1}^{n-1} [\gcd(i,n) == 1] i^d \\ =\sum_{i=1}^n \sum_{p|i,p|n} \mu(p) i^d\\ =\sum_{p|n}^n \mu(p) \sum_{i=1}^{\frac np} (ip)^d \\ = \sum_{p|n}^n \mu(p) p^d\sum_{i=1}^{\frac np} i^d i=1n1[gcd(i,n)==1]id=i=1npi,pnμ(p)id=pnnμ(p)i=1pn(ip)d=pnnμ(p)pdi=1pnid
然后对于自然数幂和我们可以用拉格朗日插值将它改写为关于上界的 d + 1 d+1 d+1次多项式:设 ∑ i = 1 x i d = ∑ i = 0 d + 1 a i x i \sum_{i=1}^x i^d = \sum_{i=0}^{d+1} a_i x^i i=1xid=i=0d+1aixi
那么原式 = ∑ p ∣ n n μ ( p ) p d ∑ i = 0 d + 1 a i ( n p ) i = ∑ i = 0 d + 1 a i ∑ p ∣ n n μ ( p ) p d ( n p ) i = \sum_{p|n}^n \mu(p) p^d\sum_{i=0}^{d+1} a_i(\frac np)^i\\ = \sum_{i=0}^{d+1} a_i\sum_{p|n}^n \mu(p) p^d(\frac np)^i =pnnμ(p)pdi=0d+1ai(pn)i=i=0d+1aipnnμ(p)pd(pn)i
那么如果可以算出后面一个和式的值久可以算出答案了。
后面一个和式发现是三个积性函数的点积,是可以在令 n = p i a i n = p_i^{a_i} n=piai的每个 i = 1.... w i=1....w i=1....w处算出答案然后乘起来得到的。

A C   C o d e \rm{AC\ Code} AC Code

#include<bits/stdc++.h>
#define maxn 1005
#define mod 1000000007
using namespace std;

int d,w,s[maxn],inv[maxn]={1,1},invf[maxn]={1,1},rinv[maxn]={1,-1},dp[maxn]={1},x[maxn],p[maxn],a[maxn];
int Pow(int base,int k){
	int ret = 1;
	for(;k;k>>=1,base=1ll*base*base%mod)
		if(k&1)
			ret=1ll*ret*base%mod;
	return ret;
}

int main(){
	scanf("%d%d",&d,&w);
	for(int i=1;i<=d+2;i++){
		s[i] = (s[i-1] + Pow(i,d)) % mod;
		for(int j=d+2;j>=0;j--)
			dp[j] = ((j ? dp[j-1] : 0) - 1ll * i * dp[j]) % mod;
	}
	for(int i=2;i<=d+2;i++) 
		inv[i] = 1ll * (mod - mod / i ) * inv[mod % i] % mod,
		invf[i] = 1ll * invf[i-1] * inv[i] % mod,
		rinv[i] = 1ll * rinv[i-1] * (-inv[i]) % mod;
	for(int i=1;i<=d+2;i++){
		for(int j=0;j<=d+2;j++){
			dp[j] = ((j ? dp[j-1] : 0) - dp[j]) * 1ll * inv[i] % mod,
			x[j] = (x[j] + dp[j] * 1ll * invf[i-1] % mod * rinv[d+2-i] % mod * s[i]) % mod;
		}
		for(int j=d+2;j>=0;j--)
			dp[j] = ((j ? dp[j-1] : 0) - 1ll * i * dp[j]) % mod;
	}
	for(int i=1;i<=w;i++) scanf("%d%d",&p[i],&a[i]);
	int ans = 0;
	for(int i=0;i<=d+1;i++){
		int prd=1;
		for(int j=1;j<=w;j++)
			prd = 1ll * prd * (Pow(Pow(p[j],a[j]),i) - 1ll * Pow(p[j],d) * Pow(Pow(p[j],a[j]-1),i) % mod) % mod;
		ans = (ans + 1ll * prd * x[i]) % mod;
	}
	printf("%d\n",(ans+mod)%mod);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值