zoukankan      html  css  js  c++  java
  • DTOJ #3160. 序列计数(count)

    【题目描述】

    Alice想要得到一个长度为 $n$ 的序列,序列中的数都是不超过 $m$ 的正整数,而且这 $n$ 个数的和是 $p$ 的倍数。

    Alice还希望,这 $n$ 个数中,至少有一个数是质数。

    Alice想知道,有多少个序列满足她的要求。

    【输入格式】

    一行三个数, $n,m,p$。

    【输出格式】

    一行一个数,满足Alice的要求的序列数量。由于满足条件的序列可能很多,输出结果对 $20170408$ 取模。

    【样例】

    样例输入
    3 5 3

    样例输出
    33

    【数据范围与提示】

    对于 $ 20 \% $ 的数据, $ 1 le n le 100,1 le m le 100 $。

    对于 $ 50 \% $ 的数据, $ 1 le m le 100 $。

    对于 $ 80 \% $ 的数据, $ 1 le m le 10^6 $。

    对于 $ 100 \% $ 的数据, $ 1 le n le 10^9,1 le m le 2 imes 10^7,1 le p le 100 $。

    【题解】

    设 $f[i][j][0/1]$ 表示前 $i$ 个数,和在 $mod p$ 意义下为 $j$,是否取了质数的方案数。

    列出转移式后用矩阵快速幂或多项式优化即可。

    【代码】

    #include<bits/stdc++.h>
    const int mod=20170408;
    int n,m,p,pr[20000010],tot;
    bool flag[20000010];
    struct Poly
    {
        int a[110];
        inline friend Poly operator + ( const Poly &p1,const Poly &p2 )
        {
            Poly p3;memset(p3.a,0,sizeof(p3.a));
            for ( int i=0;i<p;i++ ) p3.a[i]=(p1.a[i]+p2.a[i])%mod;
            return p3;
        }
        inline friend Poly operator - ( const Poly &p1,const Poly &p2 )
        {
            Poly p3;memset(p3.a,0,sizeof(p3.a));
            for ( int i=0;i<p;i++ ) p3.a[i]=(p1.a[i]-p2.a[i]+mod)%mod;
            return p3;
        }
        inline friend Poly operator * ( const Poly &p1,const Poly &p2 )
        {
            Poly p3;memset(p3.a,0,sizeof(p3.a));
            for ( int i=0;i<p;i++ ) for ( int j=0;j<p;j++ ) p3.a[(i+j)%p]=(p3.a[(i+j)%p]+1LL*p1.a[i]*p2.a[j])%mod;
            return p3;
        }
        inline friend Poly operator ^ ( Poly p,int n )
        {
            Poly res;memset(res.a,0,sizeof(res.a));res.a[0]=1;
            for ( ;n;n>>=1,p=p*p ) if ( n&1 ) res=res*p;
            return res;
        }
    }A,B;
    signed main()
    {
        scanf("%d%d%d",&n,&m,&p);
        flag[1]=true;
        for ( int i=2;i<=m;i++ )
        {
            if ( !flag[i] ) pr[++tot]=i;
            for ( int j=1;j<=tot and pr[j]*i<=m;j++ )
            {
                flag[i*pr[j]]=true;
                if ( !(j%i) ) break;
            }
        }
        for ( int i=1;i<=m;i++ ) A.a[i%p]++,B.a[i%p]+=flag[i];
        for ( int i=0;i<p;i++ ) A.a[i]%=mod,B.a[i]%=mod;
        printf("%d
    ",((A^n)-(B^n)).a[0]);
    }
  • 相关阅读:
    课后作业-阅读任务-阅读提问-3
    团队-团队编程项目作业名称-团队一阶段互评
    结对-四则运算答题器-结对项目总结
    课后作业-阅读任务-阅读笔记
    团队-科学计算器-开发文档
    团队编程项目作业6-程序维护
    课后作业-团队编程项目总结
    课后作业-阅读任务-阅读提问-4
    课后作业-阅读任务-阅读笔记-4
    个人编程作业2
  • 原文地址:https://www.cnblogs.com/RenSheYu/p/11327244.html
Copyright © 2011-2022 走看看