SDOI2017序列计数

蒟蒻来水题啦......

转移方程:dp[i][j]=∑dp[i1][(jk)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 } 
View Code

然后打了个矩乘优化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 }
View Code

然后就不会了,查题解以后才知道构造矩阵还可以优化,第一次知道还可以这样,自己真是弱,感觉要挂。

  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("
");
 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 }
View Code

话说第一次用取余构造矩阵,自己真是做题少。

原文地址:https://www.cnblogs.com/hzs2000/p/6736366.html