嗯。。。。这个式子很奇妙
化简是没有用的,考虑一个dp,答案能用这个式子表达。
于是dp[i][j]表示前i组物品选出%k=j个物品的方案数,然后矩阵加速转移。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; long long n,p,k,r,c[55][55]; struct matrix { long long a[55][55]; }ans,base; matrix operator * (matrix a,matrix b) { matrix c; for (long long i=0;i<k;i++) for (long long j=0;j<k;j++) c.a[i][j]=0; for (long long i=0;i<k;i++) for (long long j=0;j<k;j++) for (long long kk=0;kk<k;kk++) c.a[i][j]=(c.a[i][j]+a.a[i][kk]*b.a[kk][j]%p)%p; return c; } void build() { c[0][0]=1; for (long long i=1;i<=k;i++) { c[i][0]=1; for (long long j=1;j<=i;j++) c[i][j]=(c[i-1][j-1]+c[i-1][j])%p; } base.a[0][0]=2;for (long long i=1;i<k;i++) base.a[i][0]=c[k][k-i]; for (long long i=1;i<k;i++) for (long long j=0;j<k;j++) base.a[j][i]=base.a[(j-1+k)%k][i-1]; ans.a[0][0]=2;for (long long i=1;i<k;i++) ans.a[0][i]=c[k][i]; } void f_pow(long long x) { while (x) { if (x&1) ans=(ans*base); base=base*base; x>>=1; } } int main() { scanf("%lld%lld%lld%lld",&n,&p,&k,&r); build(); f_pow(n-1); printf("%lld\n",ans.a[0][r]); return 0; }