题目大意
WYF有一个精致的k维立方体盒子(2维为正方形,3维为正方体,以此类推)。这个盒子的边长为n,里面有一个边长为n-1的盒子,边长为n-1的盒子里面还有一个边长为n-2的盒子……最里面的盒子边长为m。现在WYF想知道这n-m+1个盒子的k维体积和模p的余数。
解题思路
ans=∑ni=mik%p
∑ni=0ik=∑ki=1s(k,i)(n+1)(i+1)(此处有下划线)/(i+1)
求出第二类斯特林数即可k^2求解,由于是任意模数不一定有逆元,而连续i+1个数一定有一个是i+1的倍数,这样就不用乘法了。对于模数过大,把一个数拆成两个较小的数相乘取模即可。
code
using namespace std;
LL max(LL x,LL y){return (x>y)?x:y;}
LL min(LL x,LL y){return (x<y)?x:y;}
LL const mk=2000+9,inf=1e9+7;
LL n,m,K,p,s[mk][mk];
LL mod(LL x,LL y){
LL bit=1e6,a1=x/bit,a2=x%bit,b1=y/bit,b2=y%bit;
LL tmp=(a1*b1%p*bit%p*bit%p+a1*b2%p*bit%p+b1*a2%p*bit%p+a2*b2%p)%p;
return (a1*b1%p*bit%p*bit%p+a1*b2%p*bit%p+b1*a2%p*bit%p+a2*b2%p)%p;
}
LL calc(LL n){
LL ans=0;
fo(i,0,K){
LL tmp=s[K][i];
fd(j,n+1,n+1-i)
tmp=mod(tmp,(j%(i+1)==0)?j/(i+1):j);
ans=(ans+tmp)%p;
}
return ans;
}
LL pow(LL x,LL y){
LL z=1;
while(y){
if(y&1)z=mod(z,x);
x=mod(x,x);
y>>=1;
}
return z;
}
int main(){
freopen("d.in","r",stdin);
freopen("d.out","w",stdout);
scanf("%lld%lld%lld%lld",&K,&n,&m,&p);
if(K>2000){
LL ans=0;
fo(i,m,n)
ans=(ans+pow(i,K))%p;
printf("%lld",ans);
return 0;
}
s[0][0]=1;
fo(i,1,K)fo(j,1,i)s[i][j]=(s[i-1][j-1]+j*s[i-1][j])%p;
LL tmp=calc(n),tm2=calc(m-1);
printf("%lld",((tmp-tm2)%p+p)%p);
return 0;
}