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

题目分析:

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

代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 int n,p,k,r;
 5 
 6 long long mat[56][56];
 7 long long g[56][56];
 8 long long t[56][56];
 9 
10 void fast_pow(long long pw){
11     if(pw == 1) {
12     for(int i=0;i<k;i++) for(int j=0;j<k;j++) g[i][j] = mat[i][j];
13     return;
14     }
15     fast_pow(pw/2);
16     for(int i=0;i<k;i++) for(int j=0;j<k;j++) t[i][j] = g[i][j];
17     memset(g,0,sizeof(g));
18     for(int o=0;o<k;o++){
19     for(int i=0;i<k;i++){
20         for(int j=0;j<k;j++){
21         g[i][j] += (t[i][o]*t[o][j])%p;
22         g[i][j] %= p;
23         }
24     }
25     }
26     if(pw&1){
27     for(int i=0;i<k;i++) for(int j=0;j<k;j++) t[i][j] = g[i][j];
28     memset(g,0,sizeof(g));
29     for(int o=0;o<k;o++){
30         for(int i=0;i<k;i++){
31         for(int j=0;j<k;j++){
32             g[i][j] += (t[i][o]*mat[o][j])%p;
33             g[i][j] %= p;
34         }
35         }
36     }
37     }
38 }
39 
40 void BuildMat(){
41     for(int i=0;i<k;i++){
42     mat[i][i] += 1; mat[i][(i-1+k)%k] += 1;
43     }
44 }
45 
46 void work(){
47     BuildMat();
48     fast_pow(1ll*n*k);
49     printf("%lld",g[r][0]);
50 }
51 
52 int main(){
53     scanf("%d%d%d%d",&n,&p,&k,&r);
54     work();
55     return 0;
56 }

 

posted @ 2018-05-16 22:10  menhera  阅读(267)  评论(0编辑  收藏  举报