zoukankan      html  css  js  c++  java
  • 「luogu3702」[SDOI2017]序列计数

    考虑题目中的两个限制:

    • 至少有一个数是质数:简单容斥,至少有一个数是质数的方案数=总方案数-没有一个数是质数的方案数。
    • 所有数的和是p 的倍数:因为p的范围很小,可以在模p意义下考虑。

    然后发现这是一个dp。

    dp[i][j] 表示前 i 个数的和模 p 为 j 的方案数。

    发现可以用矩阵快速幂优化。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int N=20000010,P=110,mod=20170408;
     4 int n,m,p,prime[N],tot,cnt[P],all[P];
     5 bool isp[N];
     6 void pre(){
     7     isp[1]=1,cnt[1%p]++,all[1%p]++;
     8     for(int i=2;i<=m;i++){
     9         all[i%p]++;
    10         if(!isp[i]){prime[++tot]=i;}
    11         else cnt[i%p]++;
    12         for(int j=1;j<=tot&&1LL*prime[j]*i<=m;j++){
    13             isp[i*prime[j]]=1;
    14             if(!(i%prime[j])) break;
    15         }
    16     }
    17     return;
    18 }
    19 struct Mat{
    20     int n,m,num[P][P];
    21     Mat(){
    22         n=m=0;
    23         memset(num,0,sizeof(num));
    24         return;
    25     }
    26     void set1(){for(int i=1;i<=n;i++) num[i][i]=1;return;}
    27     Mat operator*(const Mat& k)const{
    28         Mat c;
    29         c.n=n,c.m=k.m;
    30         for(int i=0;i<n;i++)
    31             for(int j=0;j<k.m;j++)
    32                 for(int ii=0;ii<m;ii++)
    33                     c.num[i][j]=((long long)c.num[i][j]+(long long)num[i][ii]*k.num[ii][j])%mod;
    34         return c;
    35     }
    36     void print(){
    37         for(int i=0;i<n;i++){
    38             for(int j=0;j<m;j++) cout<<num[i][j]<<" ";
    39             cout<<endl;
    40         }
    41         cout<<endl;
    42         return;
    43     }
    44 };
    45 void qpow(Mat x,int y,Mat& res){
    46     res.n=x.n,res.m=x.m;
    47     res.set1();
    48     while(y){
    49         if(y&1) res=res*x;
    50         x=x*x,y>>=1;
    51     }
    52     return;
    53 }
    54 
    55 int main(){
    56     scanf("%d%d%d",&n,&m,&p);
    57     pre();
    58     Mat a,b,c,d;
    59     a.n=a.m=b.n=b.m=p;
    60     c.n=d.n=p,c.m=d.m=1;
    61     for(int i=0;i<p;i++){
    62         for(int j=0;j<p;j++) a.num[i][j]=cnt[(i-j+p)%p],b.num[i][j]=all[(i-j+p)%p];
    63     }
    64     c.num[0][0]=d.num[0][0]=1;
    65     qpow(a,n-1,a);qpow(b,n-1,b);
    66     c=a*c,d=b*d;
    67     int ans=((d.num[0][0]-c.num[0][0])%mod+mod)%mod;
    68     printf("%d",ans);
    69     return 0;
    70 }
  • 相关阅读:
    扩展欧几里得(exgcd)与同余详解
    卡常模板
    文艺平衡树(区间翻转)
    Motto
    PKUWC2019划水记
    【模板】Splay(洛谷P3391)
    【PKUSC2018】最大前缀和
    【PKUWC2018】随机算法
    【PKUWC2018】Slay the Spire
    【PKUWC2018】Minimax
  • 原文地址:https://www.cnblogs.com/mycups/p/8579702.html
Copyright © 2011-2022 走看看