组合数问题题解
组合数问题题解
水题,但我为什么想不出
屈辱看题解系列~~
就是求n*k中选mod k余r 的方案数之和
我们不妨设一个dp状态:\(f[i][j]\)表示i中选mod k 余 j的方案数之和
显然,\(f[i][j]=\sum_{p=0}^{i/k} C_{i}^{p*k+j}\)
所以,它也适用于\(C_{i}^{j}=C_{i-1}^{j}+C_{i-1}^{j-1}\)的公式啦,
只是注意一下:\(f[i][0]\)可以由\(f[i-1][k-1]\)转移过来就行了。
然后,咕咕咕,就能愉快地写出转移矩阵了。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=52;
int r;
ll n,k,p;
struct matrix{
ll z[N][N];
void clr(){memset(z,0,sizeof(z));}
}g,h;
matrix operator * (matrix u,matrix v){
matrix ans; ans.clr();
for(int i=0;i<k;++i) for(int j=0;j<k;++j) for(int q=0;q<k;++q) ans.z[i][j]=(ans.z[i][j]+u.z[i][q]*v.z[q][j]%p)%p;
return ans;
}
void ksm(){
n=n*k;
while(n){
if(n&1) g=g*h;
h=h*h,n>>=1;
}
}
int main(){
scanf("%lld%lld%lld%d",&n,&p,&k,&r);
g.z[0][0]=1,++h.z[0][0],++h.z[k-1][0];
for(int i=1;i<k;++i) h.z[i-1][i]=h.z[i][i]=1;
ksm(),printf("%lld\n",g.z[0][r]);
return 0;
}