zoukankan      html  css  js  c++  java
  • 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

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

  • 相关阅读:
    kmp学习笔记(模板)
    最小表示法 (模板)
    Codeforces 1339C
    Codeforces 1339D
    Codeforces 1244C
    Codeforces 1262D2
    Codeforces 1330D
    Problem M. Mediocre String Problem
    Codeforces 1326D2
    selenium读取数据文件
  • 原文地址:https://www.cnblogs.com/hzs2000/p/6736366.html
Copyright © 2011-2022 走看看