第一次被搞。
这个套路深啊。。。。。。
∑
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=1∑n−1[gcd(i,n)==1]id=i=1∑np∣i,p∣n∑μ(p)id=p∣n∑nμ(p)i=1∑pn(ip)d=p∣n∑nμ(p)pdi=1∑pnid
然后对于自然数幂和我们可以用拉格朗日插值将它改写为关于上界的
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
=p∣n∑nμ(p)pdi=0∑d+1ai(pn)i=i=0∑d+1aip∣n∑nμ(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);
}