Description:
Solution:
设
因为要i与p互质才有逆元,所以要分类:
Part 1——i不与p互质
因为p是质数,那么这种可能只有i是p的倍数。
那么我们对这些数求和。
∑i=1⌊np⌋1i∗pmodpk
把所有的1/p提取出来
1p∑i=1⌊np⌋1imodpk
因为还要除以一个p,我们想办法把它消掉。
假如
amodb=c
,那么就是
akmodbk=ck
那么上式可以化简为
∑⌊np⌋i=11imodpk+1p
把类似f(x,y)的带进去
f(⌊np⌋,k+1)p
然后f一直递归下去
递归出口x=0时return 0
Part2——i不与p互质
如果i与p互质,那么所有的数就是
11
12
……
1p−1
.
.
.
.
.
.
1p∗(⌊np⌋−1)
1p∗(⌊np⌋−1)+1
……
1p∗(⌊np⌋)−1
还剩下一些数,用暴力求出它的和
∑i=p∗⌊np⌋n1i
但是上面那些数我们要怎么求呢?
∑i=1p−1∑a=0⌊np⌋−11ap+i
如果你知识量够广的话,如果你知道泰勒展开式的话,那就好解决了,不用百度,往下看。
因为
11−x=x0+x1+……+x∞(0<=x<1)
证明:
上面明显是等比数列,那么和为
x∞−1x−1=11−x(因为0<=x<1,那么x∞=0极限思想)
有了上面的结论之后,式子要是分母含有1和东西
那么分子分母同时乘上
i−1
∑i=1p−1∑a=0⌊np⌋−1i−1ap∗i−1+1
把 i−1 带出来
∑i=1p−1i−1∑a=0⌊np⌋−11ap∗i−1+1
那么我们设
x=−i−1ap
那么根据泰勒展开式就会变为
∑i=1p−1i−1∑a=0⌊np⌋−1∑b=0∞xb
把x还原,那么就是
∑i=1p−1i−1∑a=0⌊np⌋−1∑b=0∞(−i−1apb)
但是有∞,那么怎么算呢?
我们发现答案还是要mod
pk
的
当b=k时,就会有
−i−1apk
,这个mod
pk
是为0的,这个和后面的式子明显都有
pk
这个因数,所以并不需要统计,因为都是+0,+0,+0……
那么我们的答案就是
∑i=1p−1i−1∑a=0⌊np⌋−1∑b=0k−1(−i−1apb)
我们发现这样很难统计,我们根据乘法分配律把 ∑ 外置出来
∑i=1p−1i−1∑b=0k−1−i−1pb∑a=0⌊np⌋−1ab
那么我们在加上剩下的值,就是这一段part2的答案
注意逆元用扩展欧几里得
求自然数幂和的方法,请转移自然数幂求和的各种方法
Code
我打了个伯努利数,第三个样例过不了,OJ 100分。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define ll long long
using namespace std;
const int maxn=100007;
ll c[200][200],s[maxn];
ll i,j,k,l,t,n,m,ans,p,mo;
void exgcd(ll a,ll b,ll &x,ll &y){
if(b==0){
x=1,y=0;
return;
}
ll xx,yy;
exgcd(b,a%b,xx,yy);
x=yy;
y=xx-a/b*yy;
}
ll qsm(ll x,ll y){
ll z=1;
for(;y;y>>=1){
if(y&1)z=(z*x)%mo;
x=(x*x)%mo;
}
return z;
}
ll niyuan(ll yi){
ll x,y,z;
exgcd(yi,mo,x,y);
z=(x%mo+mo)%mo;
return z;
}
ll strling(ll x,ll y){
ll z=0,i;
if(x<0){
fo(i,0,x){
z=(z+qsm(i,y))%mo;
}
return z;
}
s[0]=1;
fo(i,1,y){
ll o=-niyuan(i+1);
ll d=0;
fo(j,0,i-1){
d=(d+c[i+1][j]*s[i]%mo+mo)%mo;
}
o=(o*d)%mo;
s[i]=o;
}
return s[y];
}
ll compute(ll x,ll ci){
if(x==0)return 0;
ll an=0,b,i;
fo(i,1,ci-1) c[i][0]=c[0][i]=1;
fo(i,1,ci-1){
fo(j,1,i){
c[i][j]=(c[i-1][j]+c[i-1][j-1])%mo;
}
}
c[0][0]=1;
fo(i,1,p-1){
ll o=niyuan(i);
fo(b,0,ci-1){
an=(an+o*qsm(-o*p%mo,b)%mo*strling(x/p-1,b)%mo)%mo;
}
}
fo(i,x/p*p+1,x){
ll o=niyuan(i);
an=(an+o)%mo;
}
ll moo=mo;
mo=mo*p;
an=(an+compute(x/p,ci+1)/p)%moo;
an=(an%moo+moo)%moo;
return an;
}
int main(){
scanf("%lld%lld%lld",&p,&k,&n);
mo=1;
fo(i,1,k)mo=mo*p;
printf("%lld\n",compute(n,k));
}
我打了个差分表,第三个样例过不了,OJ 100分。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define ll long long
using namespace std;
const int maxn=100007;
ll c[200][200],s[maxn];
ll i,j,k,l,t,n,m,ans,p,mo;
void exgcd(ll a,ll b,ll &x,ll &y){
if(b==0){
x=1,y=0;
return;
}
ll xx,yy;
exgcd(b,a%b,xx,yy);
x=yy;
y=xx-a/b*yy;
}
ll qsm(ll x,ll y){
ll z=1;
for(;y;y>>=1){
if(y&1)z=(z*x)%mo;
x=(x*x)%mo;
}
return z;
}
ll niyuan(ll yi){
ll x,y,z;
exgcd(yi,mo,x,y);
z=(x%mo+mo)%mo;
return z;
}
ll strling(ll x,ll y){
ll z=0,i;
if(x<0){
fo(i,0,x){
z=(z+qsm(i,y))%mo;
}
return z;
}
s[0]=x+1;
ll o=niyuan(2);
s[1]=x*(x+1)%mo*o%mo;
fo(i,2,y){
ll o=niyuan(i+1);
ll d=(qsm(x+1,i+1)-x-1+mo)%mo;
fo(j,2,i){
d=(d-c[i+1][j]*s[i-j+1]%mo+mo)%mo;
}
d=(d+mo)%mo;
o=(o*d)%mo;
s[i]=o;
}
return s[y];
}
ll compute(ll x,ll ci){
if(x==0)return 0;
ll an=0,b,i;
fo(i,1,ci-1) c[i][0]=c[0][i]=1;
fo(i,1,ci-1){
fo(j,1,i){
c[i][j]=(c[i-1][j]+c[i-1][j-1])%mo;
}
}
c[0][0]=1;
fo(i,1,p-1){
ll o=niyuan(i);
fo(b,0,ci-1){
an=(an+o*qsm(-o*p%mo,b)%mo*strling(x/p-1,b)%mo)%mo;
}
}
fo(i,x/p*p+1,x){
ll o=niyuan(i);
an=(an+o)%mo;
}
ll moo=mo;
mo=mo*p;
an=(an+compute(x/p,ci+1)/p)%moo;
an=(an%moo+moo)%moo;
return an;
}
int main(){
scanf("%lld%lld%lld",&p,&k,&n);
mo=1;
fo(i,1,k)mo=mo*p;
printf("%lld\n",compute(n,k));
}
但是用第一类斯特林数可以过第三个点,也可以100分
Werkey_Tom的
ll get(ll n,ll k){
su[0][0]=1;
ll i,j;
fo(i,1,k) su[i][0]=0,su[i][i]=1;
fo(i,1,k)
fo(j,1,i-1)
su[i][j]=(su[i-1][j-1]+(i-1)*su[i-1][j]%m)%m;
if (!n) return 0;
if (n<=k){
t=0;
fo(i,0,n){
l=1;
fo(j,1,k)
l=l*i%m;
t=(t+l)%m;
}
return t;
}
fo(i,0,k) f[i]=0;f[0]=(n+1)%m;
if (n%2==0) f[1]=n/2*(n+1)%m;
else f[1]=n*(n+1)/2%m;
fo(i,2,k){
t=1;
fo(j,n+1-i,n+1)
if (j%(i+1)==0) t=t*j/(i+1)%m;else t=t*j%m;
f[i]=t;
fo(j,0,i-1){
if ((j+i)%2==0) l=1;else l=-1;
f[i]=((f[i]-l*su[i][j]%m*f[j]%m)%m+m)%m;
}
f[i]=f[i]%m;
}
return f[k];
}