题意:求
∑ni=1i−1 mod pk
∑
i
=
1
n
i
−
1
m
o
d
p
k
的值。保证
p
p
为质数,
题解:神题!细节巨多!
设
f(n,k)=∑ni=1i−1 mod pk
f
(
n
,
k
)
=
∑
i
=
1
n
i
−
1
m
o
d
p
k
,
g(n,k)=∑ni=1,i≠jpi−1 mod pk
g
(
n
,
k
)
=
∑
i
=
1
,
i
≠
j
p
n
i
−
1
m
o
d
p
k
则
f(n,k)=g(n,k)+f(⌊np⌋,k+1)p
f
(
n
,
k
)
=
g
(
n
,
k
)
+
f
(
⌊
n
p
⌋
,
k
+
1
)
p
为什么后面那里是k+1呢?
因为若
a≡b mod c
a
≡
b
m
o
d
c
,则
ak≡bk mod ck
a
k
≡
b
k
m
o
d
c
k
我们把那一部分先整体乘
p
p
,最后再除回来就好。
这样我们就可以递归计算了。
如何求g(n,k)?
=∑i=a+bp<=n1i
=
∑
i
=
a
+
b
p
<=
n
1
i
=∑p−1a=1∑⌊n−ap⌋b=01a+bp
=
∑
a
=
1
p
−
1
∑
b
=
0
⌊
n
−
a
p
⌋
1
a
+
b
p
=∑p−1a=1∑⌊n−ap⌋b=0(a+bp)−1
=
∑
a
=
1
p
−
1
∑
b
=
0
⌊
n
−
a
p
⌋
(
a
+
b
p
)
−
1
这个东西用广义二项式定理展开一下
(a+bp)−1=∑∞i=0Ci−1a−1−ibipi=∑∞i=0(−1)ia−1−ibipi
(
a
+
b
p
)
−
1
=
∑
i
=
0
∞
C
−
1
i
a
−
1
−
i
b
i
p
i
=
∑
i
=
0
∞
(
−
1
)
i
a
−
1
−
i
b
i
p
i
又因为我们模了一个
pk
p
k
所以
(a+bp)−1=∑k−1i=0(−1)ia−1−ibipi
(
a
+
b
p
)
−
1
=
∑
i
=
0
k
−
1
(
−
1
)
i
a
−
1
−
i
b
i
p
i
所以
g(n,k)
g
(
n
,
k
)
=∑k−1i=0(−p)i∑p−1a=11ai+1∑⌊n−ap⌋b=0bi
=
∑
i
=
0
k
−
1
(
−
p
)
i
∑
a
=
1
p
−
1
1
a
i
+
1
∑
b
=
0
⌊
n
−
a
p
⌋
b
i
我们令
Sk(n)
S
k
(
n
)
表示
∑ni=0ik
∑
i
=
0
n
i
k
则
g(n,k)=∑k−1i=0(−p)i∑p−1a=11ai+1Si(⌊n−ap⌋)
g
(
n
,
k
)
=
∑
i
=
0
k
−
1
(
−
p
)
i
∑
a
=
1
p
−
1
1
a
i
+
1
S
i
(
⌊
n
−
a
p
⌋
)
如何求
Sk(n)?
S
k
(
n
)
?
我们先证一个东西:
xn¯¯¯=Πx+n−1i=xi=∑ks(n,k)xk
x
n
¯
=
Π
i
=
x
x
+
n
−
1
i
=
∑
k
s
(
n
,
k
)
x
k
,s是第一类斯特林数。
可以转化为证
[xp]xn¯¯¯=[xp]∑ks(n,k)xk=s(n,p)
[
x
p
]
x
n
¯
=
[
x
p
]
∑
k
s
(
n
,
k
)
x
k
=
s
(
n
,
p
)
显然在
n=1
n
=
1
的情况下是成立的。
[xk]xn¯¯¯
[
x
k
]
x
n
¯
=[xk](x+n−1)xn−1¯¯¯¯¯¯¯¯¯¯
=
[
x
k
]
(
x
+
n
−
1
)
x
n
−
1
¯
=[xk](x+n−1)xn−1¯¯¯¯¯¯¯¯¯¯
=
[
x
k
]
(
x
+
n
−
1
)
x
n
−
1
¯
=[xk]x×xn−1¯¯¯¯¯¯¯¯¯¯+[xk](n−1)xn−1¯¯¯¯¯¯¯¯¯¯
=
[
x
k
]
x
×
x
n
−
1
¯
+
[
x
k
]
(
n
−
1
)
x
n
−
1
¯
=[xk−1]xn−1¯¯¯¯¯¯¯¯¯¯+[xk](n−1)xn−1¯¯¯¯¯¯¯¯¯¯
=
[
x
k
−
1
]
x
n
−
1
¯
+
[
x
k
]
(
n
−
1
)
x
n
−
1
¯
=s(n−1,k−1)+(n−1)s(n−1,k)
=
s
(
n
−
1
,
k
−
1
)
+
(
n
−
1
)
s
(
n
−
1
,
k
)
=s(n,k)
=
s
(
n
,
k
)
证明完毕。
我们再证一个东西:
其实挺显然的,上面那个证明的式子 xn x n 的项系数为1,所以一减就可以得到这个式子。
我们还要证一个东西:
怎么证?
证明完毕。
终于要继续自然数幂求和啦!有了之前推的一堆式子,我们就可以化简式子了。
Sk(n) S k ( n )
=∑ni=0ik = ∑ i = 0 n i k
=∑ni=0k!Cki−∑k−1j=1s(k,j)ij = ∑ i = 0 n k ! C i k − ∑ j = 1 k − 1 s ( k , j ) i j
=k!(∑ni=0Cki)−∑ni=0∑k−1j=1s(k,j)ij = k ! ( ∑ i = 0 n C i k ) − ∑ i = 0 n ∑ j = 1 k − 1 s ( k , j ) i j
=k!Ck+1n+1∑k−1j=1s(k,j)∑ni=0ij = k ! C n + 1 k + 1 ∑ j = 1 k − 1 s ( k , j ) ∑ i = 0 n i j
对于固定的 n n ,这个可以预处理出来。然后代会这个式子里计算。
g(n,k)=∑k−1i=0(−p)i∑p−1a=11ai+1Si(⌊n−ap⌋) g ( n , k ) = ∑ i = 0 k − 1 ( − p ) i ∑ a = 1 p − 1 1 a i + 1 S i ( ⌊ n − a p ⌋ )
对于一些零碎的部分,我是直接暴力计算的。
这一题数域可能很大,我写了 O(1) O ( 1 ) 快速乘法。
这题好难写啊!QAQ
代码
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define int long long
using namespace std;
int p,k,n,x,y,r[100005],s[105][105];
int mul(int a,int b,int mod){
int c=a*(double)b/mod+0.5;
int res=a*b-c*mod;
if(res<0){
res+=mod;
}
return res;
}
int fastpow(int a,int x,int mod){
a%=mod;
int res=1;
while(x){
if(x&1){
res=mul(res,a,mod);
}
x>>=1;
a=mul(a,a,mod);
}
return res;
}
int exgcd(int a,int b,int &x,int &y){
if(!b){
x=1;
y=0;
return a;
}
int d=exgcd(b,a%b,y,x);
y-=a/b*x;
return d;
}
int getinv(int a,int b){
exgcd(a,b,x,y);
return (x%b+b)%b;
}
void init(int n,int k){
const int mod=pow(p,k);
r[0]=n+1;
s[0][0]=1;
for(int i=1;i<=k;i++){
for(int j=1;j<=k;j++){
s[i][j]=(s[i-1][j-1]+mul(s[i-1][j],i-1,mod))%mod;
}
}
for(int i=1;i<=k;i++){
for(int j=1;j<=i;j++){
if((i+j)&1){
s[i][j]=mod-s[i][j];
}
}
}
for(int i=1;i<=k;i++){
r[i]=1;
bool flag=false;
for(int j=n+1;j>=n-i+1;j--){
if(!flag&&j%(i+1)==0){
flag=true;
r[i]=mul(r[i],j/(i+1),mod);
}else{
r[i]=mul(r[i],j,mod);
}
}
if(!flag){
r[i]=mul(r[i],getinv(i+1,mod),mod);
}
for(int j=1;j<i;j++){
r[i]=(r[i]-mul(s[i][j],r[j],mod)+mod)%mod;
}
}
return;
}
int g(int n,int k){
const int mod=pow(p,k);
int rem=n%p,res=0;
for(int i=n-rem+1;i<=n;i++){
res=(res+getinv(i,mod))%mod;
}
n-=rem;
if(!n){
return res;
}
init((n-1)/p,k);
for(int i=0,base=1;i<k;i++,base=(base*(-p)%mod+mod)%mod){
for(int j=1;j<p;j++){
res=(res+mul(mul(base,getinv(fastpow(j,i+1,mod),mod),mod),r[i],mod))%mod;
}
}
return res;
}
int f(int n,int k){
if(!n){
return 0;
}
return (g(n,k)+f(n/p,k+1)/p)%(int)(pow(p,k));
}
signed main(){
scanf("%lld%lld%lld",&p,&k,&n);
printf("%lld\n",f(n,k));
return 0;
}