BZOJ4870 [六省联考2017] 组合数问题 【快速幂】

时间:2021-01-12 23:23:13

题目分析:

  构造f[nk][r]表示题目中要求的东西。容易发现递推公式f[nk][r]=f[nk-1][r]+f[nk-1][(r-1)%k].矩阵快速幂可以优化,时间复杂度O(k^3logn)。

代码:

 #include<bits/stdc++.h>
using namespace std; int n,p,k,r; long long mat[][];
long long g[][];
long long t[][]; void fast_pow(long long pw){
if(pw == ) {
for(int i=;i<k;i++) for(int j=;j<k;j++) g[i][j] = mat[i][j];
return;
}
fast_pow(pw/);
for(int i=;i<k;i++) for(int j=;j<k;j++) t[i][j] = g[i][j];
memset(g,,sizeof(g));
for(int o=;o<k;o++){
for(int i=;i<k;i++){
for(int j=;j<k;j++){
g[i][j] += (t[i][o]*t[o][j])%p;
g[i][j] %= p;
}
}
}
if(pw&){
for(int i=;i<k;i++) for(int j=;j<k;j++) t[i][j] = g[i][j];
memset(g,,sizeof(g));
for(int o=;o<k;o++){
for(int i=;i<k;i++){
for(int j=;j<k;j++){
g[i][j] += (t[i][o]*mat[o][j])%p;
g[i][j] %= p;
}
}
}
}
} void BuildMat(){
for(int i=;i<k;i++){
mat[i][i] += ; mat[i][(i-+k)%k] += ;
}
} void work(){
BuildMat();
fast_pow(1ll*n*k);
printf("%lld",g[r][]);
} int main(){
scanf("%d%d%d%d",&n,&p,&k,&r);
work();
return ;
}