传送门biu~
题目可以转化为从nk个物品中选出模k等于r个物品模p的方案数。
令f[i][j]代表从i个物品中选出模k等于j个物品的方案数,则f[i][j]=f[i-1][j-1]+f[i-1][j]。因为每层f[i]的值都是由f[i-1]层推过来的,所以可以用矩阵乘法优化。
#include<bits/stdc++.h>
using namespace std;
int n,p,k,r;
struct Matrix{
int a[55][55];
Matrix operator* (const Matrix&r)const{
Matrix tmp;
for(int i=0;i<k;++i)
for(int j=0;j<k;++j){
tmp.a[i][j]=0;
for(int h=0;h<k;++h)
tmp.a[i][j]=(tmp.a[i][j]+1ll*a[i][h]*r.a[h][j])%p;
}
return tmp;
}
}base;
Matrix ksm(Matrix p,long long n){
--n;Matrix re=base;
while(n){
if(n&1) re=re*p;
p=p*p;
n>>=1;
}
return re;
}
int main(){
scanf("%d%d%d%d",&n,&p,&k,&r);
for(int i=0;i<k;++i) ++base.a[(i-1+k)%k][i],++base.a[i][i];
Matrix ans=ksm(base,1ll*n*k);
printf("%d\n",ans.a[0][r]);
return 0;
}