设
因为p是质数,那么这种可能只有i是p的倍数。
那么我们对这些数求和。
把所有的1/p提取出来
因为还要除以一个p,我们想办法把它消掉。
假如 amodb=c ,那么就是 akmodbk=ck
那么上式可以化简为
把类似f(x,y)的带进去
然后f一直递归下去
递归出口x=0时return 0
如果i与p互质,那么所有的数就是
11 12 …… 1p−1
.
.
.
.
.
.
1p∗(⌊np⌋−1) 1p∗(⌊np⌋−1)+1 …… 1p∗(⌊np⌋)−1
还剩下一些数,用暴力求出它的和
但是上面那些数我们要怎么求呢?
如果你知识量够广的话,如果你知道泰勒展开式的话,那就好解决了,不用百度,往下看。
因为
证明:
上面明显是等比数列,那么和为
有了上面的结论之后,式子要是分母含有1和东西
那么分子分母同时乘上 i−1
把 i−1 带出来
那么我们设 x=−i−1ap
那么根据泰勒展开式就会变为
把x还原,那么就是
但是有∞,那么怎么算呢?
我们发现答案还是要mod pk 的
当b=k时,就会有 −i−1apk ,这个mod pk 是为0的,这个和后面的式子明显都有 pk 这个因数,所以并不需要统计,因为都是+0,+0,+0……
那么我们的答案就是
我们发现这样很难统计,我们根据乘法分配律把 ∑ 外置出来
那么我们在加上剩下的值,就是这一段part2的答案
注意逆元用扩展欧几里得
求自然数幂和的方法,请转移自然数幂求和的各种方法
我打了个伯努利数,第三个样例过不了,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];
}