• bzoj 4818 [Sdoi2017]序列计数


    题面

    https://www.lydsy.com/JudgeOnline/problem.php?id=4818

    题解

    显然dp

    首先不考虑一定有一个质数的条件

    令$f[i][j]$表示当前选择$i$个数,当前选择的数的和模$p$等于$j$的方案数

    那么转移方程很好写

    $$f[i+1][j]= sum_{x=0}^{p-1} {f[i][(j-x+p) mod p] imes sum[x]}$$

    $sum[x]$ 表示模$p$等于$x$的数的个数

    然后选择至少一个质数的方案数=所有的方案数-没有质数的方案数

    只要改一下$sum$数组把质数都减掉再做一遍就好了

    那么每一次做的时候肯定用矩阵快速幂

    我们发现

    这样的矩阵就可以了

    f[i][0]   f[i][1]   ...   f[i][p-1]         sum[0]   sum[1]   ...   sum[p-1]

    f[i][0]   f[i][1]   ...   f[i][p-1]         *         sum[p-1]   sum[0]   ...   sum[p-2]

     ...        ...               ...                   ....         ...                    ...

    f[i][0]   f[i][1]   ...   f[i][p-1]         sum[1]   sum[2]   ...    sum[0]

    就能够得到

    f[i+1][0]   f[i+1][1]   ...   f[i+1][p-1]

    f[i+1][0]   f[i+1][1]   ...   f[i+1][p-1]

     ....           ...                   ...

    f[i+1][0]   f[i+1][1]   ...   f[i+1][p-1]

    这样就做完了

    Code

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 
     5 ll read(){
     6     ll x=0,f=1;char c=getchar();
     7     while(c<'0' || c>'9'){if(c=='-')f=-1;c=getchar();}
     8     while(c>='0' && c<='9'){x=x*10+c-'0';c=getchar();}
     9     return x*f;
    10 }
    11 
    12 const int mod=20170408;
    13 
    14 int sum[110];
    15 int n,m,p;
    16 bool isp[20000200];
    17 int pr[20000200],cnt;
    18 struct Matrix{
    19     int a[110][110];
    20     Matrix(){
    21         memset(a,0,sizeof(a));
    22         for(int i=0;i<=p;i++)
    23             a[i][i]=1;
    24     }
    25     void clear(){
    26         memset(a,0,sizeof(a));
    27     }
    28     void get(){
    29         for(int i=0;i<p;i++)
    30             for(int j=0;j<p;j++)
    31                 a[i][j]=sum[(j-i+p)%p];
    32     }
    33     Matrix operator *(Matrix b){
    34         Matrix ret;
    35         ret.clear();
    36         for(int i=0;i<p;i++)
    37             for(int j=0;j<p;j++)
    38                 for(int k=0;k<p;k++)
    39                     ret.a[i][j]=(ret.a[i][j]+a[i][k]*1ll*b.a[k][j]%mod)%mod;
    40         return ret;
    41     }
    42 } mat;
    43 Matrix ksm(Matrix a,int t){
    44     Matrix ret;
    45     while(t){
    46         if(t&1) ret=ret*a;
    47         a=a*a;
    48         t=t>>1;
    49     }
    50     return ret;
    51 }
    52 
    53 int main(){
    54 #ifdef LZT
    55     freopen("in","r",stdin);
    56 #endif
    57     n=read(),m=read(),p=read();
    58     for(int i=0;i<p;i++)
    59         sum[i]=(m-i)/p+(i<=m);
    60     sum[0]--;
    61     mat.get();
    62     mat=ksm(mat,n);
    63     int ans=mat.a[0][0];
    64     memset(isp,1,sizeof(isp));
    65     isp[1]=0;
    66     for(int i=2;i<=m;i++){
    67         if(isp[i]) pr[++cnt]=i;
    68         for(int j=1;j<=cnt && i*pr[j]<=m;j++){
    69             isp[i*pr[j]]=0;
    70             if(i%pr[j]==0) break;
    71         }
    72     }
    73     for(int i=1;i<=cnt;i++)
    74         sum[pr[i]%p]--;
    75     mat.get();
    76     mat=ksm(mat,n);
    77     ans=(ans-mat.a[0][0]+mod)%mod;
    78     printf("%d
    ",ans);
    79     return 0;
    80 }
    View Code

    Review

    比较容易的一道题

  • 相关阅读:
    项目经理必备的8个要素:沟通、总结、懂技术
    完工概率计算总结
    PMP--可能会涉及到的计算题
    六顶思考帽子法
    预测技术
    React.Component与React.PureComponent的区别
    简单理解JavaScript,TypeScript和JSX
    自己常用的linux命令
    ES6 promise 用法
    node的express框架接收get/post请求时,参数获取方式
  • 原文地址:https://www.cnblogs.com/wawawa8/p/9348556.html
Copyright © 2020-2023  润新知