zoukankan      html  css  js  c++  java
  • BZOJ_4818_[Sdoi2017]序列计数_矩阵乘法

    BZOJ_4818_[Sdoi2017]序列计数_矩阵乘法

    Description

    Alice想要得到一个长度为n的序列,序列中的数都是不超过m的正整数,而且这n个数的和是p的倍数。Alice还希望
    ,这n个数中,至少有一个数是质数。Alice想知道,有多少个序列满足她的要求。

    Input

    一行三个数,n,m,p。
    1<=n<=10^9,1<=m<=2×10^7,1<=p<=100

    Output

    一行一个数,满足Alice的要求的序列数量,答案对20170408取模。

    Sample Input

    3 5 3

    Sample Output

    33
     

    求至少有一个质数的方案可以用总方案减去不含质数的方案。
    先把1~m的质数筛出来,观察p特别小,考虑每个数%p的值对答案的贡献。
    设F[i][j]表示从%p=i到%p=j的方案数,这个矩阵乘1次相当于向序列里多塞了个数,于是这道题变成了矩阵乘法。
    然后发现f[i][j]=f[i+1][j+1],因此只需要对每个1~m中的i,f[0][i%p]++即可,剩下的可以通过平移得到。
     
    代码:
    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    ll mod=20170408;
    int n,m,p,prime[7000050],cnt;
    bool vis[20000050];
    struct Mat {
        ll v[105][105];
        Mat() {memset(v,0,sizeof(v));}
        Mat operator*(const Mat a) const {
            Mat ans;
            int i,j,k;
            for(i=1;i<=p;i++)
                for(j=1;j<=p;j++)
                    for(k=1;k<=p;k++)
                        (ans.v[i][j]+=v[i][k]*a.v[k][j])%=mod;
            return ans;
        }
    }A,B;
    Mat pow(Mat x,int y) {
        Mat I;
        int i;
        for(i=1;i<=p;i++) I.v[i][i]=1;
        while(y) {
            if(y&1) I=I*x;
            x=x*x;
            y>>=1;
        }
        return I;
    }
    void init() {
        register int i,j;
        vis[1]=1;
        for(i=2;i<=m;i++) {
            if(!vis[i]) {
                prime[++cnt]=i;
            }
            for(j=1;j<=cnt&&i*prime[j]<=m;j++) {
                vis[i*prime[j]]=1;
                if(i%prime[j]==0) break;
            }
        }
    }
    int main() {
        int i,j;
        scanf("%d%d%d",&n,&m,&p);
        init();
        for(i=1;i<=m;i++) {
            A.v[p][(i-1)%p+1]++;
            if(vis[i]) B.v[p][(i-1)%p+1]++;
        }
        for(i=p-1;i;i--) {
            for(j=1;j<=p;j++) {
                A.v[i][j]=A.v[i+1][j%p+1];
                B.v[i][j]=B.v[i+1][j%p+1];
            }
        }
        printf("%lld
    ",(pow(A,n).v[p][p]-pow(B,n).v[p][p]+mod)%mod);
    }
    
  • 相关阅读:
    移动端输入框的那些事
    HTML的各个标签的默认样式
    window.location.Reload()和window.location.href 区别
    JavaScript惰性函数定义
    JavaScript将具有父子关系的原始数据格式化成树形结构数据(id,pid)
    jQuery验证控件jquery.validate.js使用说明+中文API
    统计网页浏览次数
    vue 组件开发 props 验证
    vue过滤器在v2.0版本用法
    JQ中get()与eq()的区别
  • 原文地址:https://www.cnblogs.com/suika/p/8832021.html
Copyright © 2011-2022 走看看