bzoj-4870-组合dp+矩阵幂
4870: [Shoi2017]组合数问题
Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 829 Solved: 446
[Submit][Status][Discuss]
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
注意到问题就是求从n*k件物品中选出若干件使得选出的物品的数量%K=R的不同方案个数,f[i][j]表示从前i件物品中选出若干件满足选出物品的数量%K=j的方案个数,有f[i][j]=f[i-1][j]+f[i-1][((j-1)+K)%K],显然利用矩阵幂可以快速转移,注意特判下K=1的情况。由于快速幂传参写的是int,但是N*K可能爆int一直WA最后才发现= =
1 #include<iostream> 2 #include<cstring> 3 #include<queue> 4 #include<cstdio> 5 #include<stack> 6 #include<set> 7 #include<map> 8 #include<cmath> 9 #include<ctime> 10 #include<time.h> 11 #include<algorithm> 12 #include<bits/stdc++.h> 13 using namespace std; 14 #define mp make_pair 15 #define pb push_back 16 #define debug puts("debug") 17 #define LL long long 18 #define ULL unsigned long long 19 #define uint unsigned int 20 #define pii pair<int,int> 21 #define eps 1e-10 22 #define inf 0x3f3f3f3f 23 24 LL N,P,K,R; 25 LL qpow(LL a,LL b,LL p){ 26 LL r=1; 27 while(b){ 28 if(b&1) r=r*a%p; 29 a=a*a%p; 30 b>>=1; 31 } 32 return r; 33 } 34 struct matrix{ 35 LL a[55][55]; 36 matrix(){ 37 memset(a,0,sizeof(a)); 38 } 39 matrix operator*(matrix& tmp){ 40 matrix ans; 41 for(int i=0;i<K;++i){ 42 for(int j=0;j<K;++j){ 43 for(int k=0;k<K;++k){ 44 (ans.a[i][k]+=a[i][j]*tmp.a[j][k])%=P; 45 } 46 } 47 } 48 return ans; 49 } 50 }A,I; 51 matrix qpow(matrix X,LL n){ 52 matrix ans=I; 53 while(n){ 54 if(n&1) ans=ans*X; 55 X=X*X; 56 n>>=1; 57 } 58 return ans; 59 } 60 int main(){ 61 62 scanf("%lld%lld%lld%lld",&N,&P,&K,&R); 63 N*=K; 64 if(K==1){ 65 printf("%lld\n",qpow(2,N,P)); 66 } 67 else{ 68 for(int i=0;i<K;++i) I.a[i][i]=1; 69 A.a[0][0]=A.a[0][K-1]=1; 70 for(int i=1;i<K;++i){ 71 A.a[i][i]=A.a[i][i-1]=1; 72 } 73 matrix ans=qpow(A,N); 74 printf("%lld\n",ans.a[R][0]); 75 } 76 return 0; 77 }