BZOJ4870: [Shoi2017]组合数问题

4870: [Shoi2017]组合数问题

Description

Input

第一行有四个整数 n, p, k, r,所有整数含义见问题描述。
1 ≤ n ≤ 10^9, 0 ≤ r < k ≤ 50, 2 ≤ p ≤ 2^30 − 1

Output

一行一个整数代表答案。

Sample Input

2 10007 2 0

Sample Output

8

HINT

 

Source


dp+矩阵快速幂
很坑的就是k会等于1
所以不能写A.a[i][i]=1,A.a[i][(i-1+k)%k]=1
应该写A.a[i][i]++,A.a[i][(i-1+k)%k]++;
 1 /**************************************************************
 2     Problem: 4870
 3     User: white_hat_hacker
 4     Language: C++
 5     Result: Accepted
 6     Time:680 ms
 7     Memory:820 kb
 8 ****************************************************************/
 9  
10 #include<cstdio>
11 #include<cstdlib>
12 #include<algorithm>
13 #include<cstring>
14 #define ll long long
15 #define MAXN 52
16 using namespace std;
17 ll n,p,k,r;
18 struct Mat{
19     ll a[MAXN][MAXN];
20     Mat(){
21         memset(a,0,sizeof(a));
22     }
23     void operator *= (const Mat &B){
24         ll ret[MAXN][MAXN];
25         memset(ret,0,sizeof(ret));
26         for(int i=0;i<k;i++){
27             for(int j=0;j<k;j++){
28                 for(int q=0;q<k;q++){
29                     ret[i][j]=(ret[i][j]+a[i][q]*B.a[q][j])%p;
30                 }
31             }
32         }
33         memcpy(a,ret,sizeof(a));
34     }
35 };
36 int main()
37 {
38     Mat A,B;
39     scanf("%lld%lld%lld%lld",&n,&p,&k,&r);
40     ll b=n*k;
41     for(int i=0;i<k;i++){
42         A.a[i][i]++,A.a[i][(i-1+k)%k]++;
43         B.a[i][i]=1;
44     }
45     while(b){
46         if(b&1){
47             B*=A;
48         }
49         b>>=1;
50         A*=A;
51     }
52     printf("%lld\n",B.a[r][0]);
53     return 0;
54 }
55 

 

posted @ 2017-10-25 00:45  white_hat_hacker  阅读(224)  评论(0编辑  收藏  举报