SDOI2017序列计数
蒟蒻来水题啦......
转移方程:dp[i][j]=∑dp[i−1][(j−k)modp] i表示到第i个位置,j表示%p的余数,k表示枚举当前位置放的数1<=k<=m。
对于正常情况和一个质数都不用的分别算一下,减一下就好了,最后答案是dp[n][0];
一看题发现似乎做过,然后就写了个朴素的O(n*p*m),然后20分。
1 #include<stdio.h> 2 #include<string.h> 3 #define mo 20170408 4 int n,m,p,pri[2000005],pcont,dp[105][105],ans; 5 bool isnp[20000005]; 6 void init(); 7 int main() 8 { 9 scanf("%d%d%d",&n,&m,&p); 10 init(); int i,j,k,sb; 11 for(i=1;i<=m;i++) dp[1][i%p]++; 12 for(i=1;i<n;i++) 13 { 14 for(j=0;j<p;j++) 15 { 16 for(k=1;k<=m;k++) 17 { 18 sb = (j+k)%p; 19 dp[i+1][sb] += dp[i][j]; 20 if(dp[i+1][sb]>=mo) dp[i+1][sb]%=mo; 21 } 22 } 23 } 24 ans = dp[i][0]; 25 memset(dp,0,sizeof(dp)); 26 for(i=1;i<=m;i++){if(isnp[i]) dp[1][i%p]++;} 27 for(i=1;i<n;i++) 28 { 29 for(j=0;j<p;j++) 30 { 31 for(k=1;k<=m;k++) 32 { 33 if(isnp[k]) 34 { 35 sb = (j+k)%p; 36 dp[i+1][sb] += dp[i][j]; 37 if(dp[i+1][sb]>=mo) dp[i+1][sb]%=mo; 38 } 39 } 40 } 41 } 42 printf("%d",(ans-dp[i][0]+mo)%mo); 43 return 0; 44 } 45 void init() 46 { 47 int i,j; isnp[1] = true; 48 for(i=2;i<=m;i++) 49 { 50 if(!isnp[i]) pri[++pcont] = i; 51 for(j=1;j<=pcont;j++) 52 { 53 if(i*pri[j]>m) break; 54 isnp[i*pri[j]] = true; 55 if(i%pri[j]==0) break; 56 } 57 } 58 }
然后打了个矩乘优化O(p*m),80分。
1 #include<stdio.h> 2 #include<string.h> 3 #define lll long long 4 #define mo 20170408 5 int n,m,p,pri[2000005],pcont,dp[105]; 6 lll ans; 7 bool isnp[20000005]; 8 void init(); 9 struct mat 10 { 11 lll ori[105][105]; 12 mat operator * (const mat &y) const 13 { 14 mat ret; 15 int i,j,k; 16 for(i=0;i<p;i++) 17 for(j=0;j<p;j++) 18 { 19 ret.ori[i][j] = 0; 20 for(k=0;k<p;k++) 21 { 22 ret.ori[i][j] += (ori[i][k]*y.ori[k][j])%mo; 23 if(ret.ori[i][j]>=mo) ret.ori[i][j]%=mo; 24 } 25 } 26 return ret; 27 } 28 }; 29 mat A,B; 30 mat ksm(mat,int); 31 void solve1(); 32 void solve2(); 33 int main() 34 { 35 scanf("%d%d%d",&n,&m,&p); 36 init(); solve1(); solve2(); 37 printf("%lld",ans); 38 return 0; 39 } 40 void init() 41 { 42 int i,j; isnp[1] = true; 43 for(i=2;i<=m;i++) 44 { 45 if(!isnp[i]) pri[++pcont] = i; 46 for(j=1;j<=pcont;j++) 47 { 48 if(i*pri[j]>m) break; 49 isnp[i*pri[j]] = true; 50 if(i%pri[j]==0) break; 51 } 52 } 53 } 54 mat ksm(mat x,int n) 55 { 56 mat ret = x; n--; 57 while(n) 58 { 59 if(n&1) ret = ret*x; 60 x = x*x; 61 n >>= 1; 62 } 63 return ret; 64 } 65 void solve1() 66 { 67 int i,j; 68 for(i=1;i<=m;i++) dp[i%p]++; 69 for(i=0;i<p;i++) 70 for(j=1;j<=m;j++) 71 A.ori[((i-j)%p+p)%p][i]++; 72 A = ksm(A,n-1); 73 for(i=0;i<p;i++) 74 { 75 ans += dp[i]*A.ori[i][0]%mo; 76 if(ans>=mo) ans %= mo; 77 } 78 } 79 void solve2() 80 { 81 memset(dp,0,sizeof(dp)); 82 int i,j; 83 for(i=1;i<=m;i++){if(isnp[i]) dp[i%p]++;} 84 for(i=0;i<p;i++) 85 for(j=1;j<=m;j++) 86 if(isnp[j]){B.ori[((i-j)%p+p)%p][i]++;} 87 B = ksm(B,n-1); 88 lll ans1 = 0; 89 for(i=0;i<p;i++) 90 { 91 ans1 += dp[i]*B.ori[i][0]%mo; 92 if(ans1>=mo) ans1 %= mo; 93 } 94 ans = (ans-ans1+mo)%mo; 95 }
然后就不会了,查题解以后才知道构造矩阵还可以优化,第一次知道还可以这样,自己真是弱,感觉要挂。
1 #include<string.h> 2 #define lll long long 3 #define mo 20170408 4 int n,m,p,pri[2000005],pcont,dp[105]; 5 lll ans; 6 bool isnp[20000005]; 7 void init(); 8 struct mat 9 { 10 lll ori[105][105]; 11 mat operator * (const mat &y) const 12 { 13 mat ret; 14 int i,j,k; 15 for(i=0;i<p;i++) 16 for(j=0;j<p;j++) 17 { 18 ret.ori[i][j] = 0; 19 for(k=0;k<p;k++) 20 { 21 ret.ori[i][j] += (ori[i][k]*y.ori[k][j])%mo; 22 if(ret.ori[i][j]>=mo) ret.ori[i][j]%=mo; 23 } 24 } 25 return ret; 26 } 27 void show() 28 { 29 int i,j; 30 for(i=0;i<p;i++) 31 { 32 for(j=0;j<p;j++) printf("%lld ",ori[i][j]); 33 printf("\n"); 34 } 35 } 36 }; 37 mat A,B; 38 mat ksm(mat,int); 39 void solve1(); 40 void solve2(); 41 int main() 42 { 43 scanf("%d%d%d",&n,&m,&p); 44 init(); solve1(); solve2(); 45 printf("%lld",ans); 46 return 0; 47 } 48 void init() 49 { 50 int i,j; isnp[1] = true; 51 for(i=2;i<=m;i++) 52 { 53 if(!isnp[i]) pri[++pcont] = i; 54 for(j=1;j<=pcont;j++) 55 { 56 if(i*pri[j]>m) break; 57 isnp[i*pri[j]] = true; 58 if(i%pri[j]==0) break; 59 } 60 } 61 } 62 mat ksm(mat x,int n) 63 { 64 mat ret = x; n--; 65 while(n) 66 { 67 if(n&1) ret = ret*x; 68 x = x*x; 69 n >>= 1; 70 } 71 return ret; 72 } 73 void solve1() 74 { 75 int i,j; 76 for(i=1;i<=m;i++) dp[i%p]++; 77 for(i=1;i<=m;i++) A.ori[((-i)%p+p)%p][0]++; 78 for (i=1;i<p;i++) 79 for (j=0;j<p;j++) 80 A.ori[j][i]=A.ori[(j-1+p)%p][i-1]; 81 //A.show(); 82 A = ksm(A,n-1); 83 for(i=0;i<p;i++) 84 { 85 ans += dp[i]*A.ori[i][0]%mo; 86 if(ans>=mo) ans %= mo; 87 } 88 } 89 void solve2() 90 { 91 memset(dp,0,sizeof(dp)); 92 int i,j; 93 for(i=1;i<=m;i++){if(isnp[i]) dp[i%p]++;} 94 for(i=1;i<=m;i++){if(isnp[i])B.ori[((-i)%p+p)%p][0]++;} 95 for (i=1;i<p;i++) 96 for (j=0;j<p;j++) 97 B.ori[j][i]=B.ori[(j-1+p)%p][i-1]; 98 B = ksm(B,n-1); 99 lll ans1 = 0; 100 for(i=0;i<p;i++) 101 { 102 ans1 += dp[i]*B.ori[i][0]%mo; 103 if(ans1>=mo) ans1 %= mo; 104 } 105 ans = (ans-ans1+mo)%mo; 106 }
话说第一次用取余构造矩阵,自己真是做题少。