1. 程式人生 > >BZOJ4818 [SDOI2017] 序列計數 【矩陣快速冪】

BZOJ4818 [SDOI2017] 序列計數 【矩陣快速冪】

void 所有 num ret con esp span 相同 std

題目分析:

一個很顯然的同類項合並。註意到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 }

BZOJ4818 [SDOI2017] 序列計數 【矩陣快速冪】