BZOJ4818 [SDOI2017] 序列计数 【矩阵快速幂】
题目分析:
一个很显然的同类项合并。注意到p的大小最大为100,考虑把模p意义下相同的求出来最后所有的减去没有质数的做矩阵快速幂即可。
代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 const int maxn = 20000005; 5 6 const int mod = 20170408; 7 8 int n,m,q; 9 10 int base[105][2]; 11 12 int flag[maxn],prime[maxn/10],num; 13 14 int mat[105][105],Res[105][105],po[105][105]; 15 16 void init(){ 17 flag[1] = 1; 18 for(int i=2;i<=m;i++){ 19 if(!flag[i]) prime[++num] = i; 20 for(int j=1;j<=num&&i*prime[j]<=m;j++){ 21 flag[i*prime[j]] = 1; 22 if(i%prime[j] == 0) break; 23 } 24 } 25 for(int i=1;i<=m;i++){ 26 if(flag[i]) base[i%q][1]++; 27 base[i%q][0]++; 28 } 29 } 30 31 void BuildMatrix(int now){ 32 memset(mat,0,sizeof(mat)); 33 for(int i=0;i<q;i++){ 34 for(int j=0;j<q;j++){ 35 int nw = j-i;if(nw < 0) nw += q; 36 mat[j][nw] += base[i][now]; 37 } 38 } 39 } 40 41 void fast_pow(int now){ 42 if(now == 1){ 43 for(int i=0;i<q;i++) for(int j=0;j<q;j++) Res[i][j]=mat[i][j]; 44 }else{ 45 fast_pow(now/2); 46 memset(po,0,sizeof(po)); 47 for(int k=0;k<q;k++) 48 for(int i=0;i<q;i++) 49 for(int j=0;j<q;j++){ 50 po[i][j] += (1ll*Res[i][k]*Res[k][j])%mod; 51 po[i][j] %= mod; 52 } 53 for(int i=0;i<q;i++)for(int j=0;j<q;j++)Res[i][j]=po[i][j]; 54 if(now & 1){ 55 memset(po,0,sizeof(po)); 56 for(int k=0;k<q;k++) 57 for(int i=0;i<q;i++) 58 for(int j=0;j<q;j++){ 59 po[i][j] += (1ll*Res[i][k]*mat[k][j])%mod; 60 po[i][j] %= mod; 61 } 62 for(int i=0;i<q;i++)for(int j=0;j<q;j++)Res[i][j]=po[i][j]; 63 } 64 } 65 } 66 67 void work(){ 68 BuildMatrix(0); 69 fast_pow(n); 70 int ans = Res[0][0]; 71 BuildMatrix(1); 72 fast_pow(n); 73 ans -= Res[0][0]; 74 if(ans < 0) ans += mod; 75 printf("%d",ans); 76 } 77 78 int main(){ 79 scanf("%d%d%d",&n,&m,&q); 80 init(); 81 work(); 82 return 0; 83 }