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