[bzoj4818][Sdoi2017]序列计数

Posted FallDream

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[bzoj4818][Sdoi2017]序列计数相关的知识,希望对你有一定的参考价值。

 来自FallDream,未经允许,请勿转载,谢谢。

 Alice想要得到一个长度为n的序列,序列中的数都是不超过m的正整数,而且这n个数的和是p的倍数。Alice还希望,这n个数中,至少有一个数是质数。Alice想知道,有多少个序列满足她的要求。答案取模20170408
n<=10^9 m<=2*10^7 p<=100 
题解:考虑计算任意选择的答案 然后把质数去掉,再算一次答案,求差即可。
然后这道题数据范围好水啊 p只有100  瞎矩阵乘法都能过 那个要k^3logn
当然,直接生成函数快速幂也是一样的 只有k^2logn 基本就是模板了  
然后我就不知道怎么继续优化了 模数太奇怪没法ntt  而且数据只有100说不准常数一大跑的还没k^2快
#include<iostream>
#include<cstdio>
#include<cstring>
#define mod 20170408
using namespace std;
inline int read()
{
    int x = 0; char ch = getchar();
    while(ch < 0 || ch > 9)ch = getchar();
    while(ch >= 0 && ch <= 9){x = x * 10 + ch - 0;ch = getchar();}
    return x;
}

int n,m,p,a[205],b[205],s[mod],num=0,c[205],d[205],C[205];
bool mark[mod];

void mul(int*A,int*B)
{
    memset(C,0,sizeof(C));
    for(register int i=0;i<p;i++)
        for(register int j=0;j<p;j++)
            C[i+j]=(C[i+j]+1LL*A[i]*B[j])%mod;
    for(int i=p-1;i>=0;i--) A[i]=C[i]+C[i+p];
}

int main()
{
    n=read();m=read();p=read();
    for(register int i=0;i<p;i++) a[i]=b[i]=m/p+(m%p>=i)-(i==0); 
    for(register int i=2;i<=m;i++)
    {
        if(!mark[i]) s[++num]=i,--b[i%p];
        for(register int j=1;s[j]*i<=m;j++)
        {
            mark[s[j]*i]=1;
            if(i%s[j]==0) break;
        }
    }
    for(c[0]=d[0]=1;n;n>>=1,mul(a,a),mul(b,b))
        if(n&1) mul(c,a),mul(d,b);
    printf("%d\n",(c[0]-d[0]+mod)%mod);
    return 0;
}

 

以上是关于[bzoj4818][Sdoi2017]序列计数的主要内容,如果未能解决你的问题,请参考以下文章

bzoj4818 Sdoi2017—序列计数

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

[bzoj4818][Sdoi2017]序列计数

[bzoj4818][Sdoi2017]序列计数_矩阵乘法_欧拉筛

bzoj 4818: [Sdoi2017]序列计数

BZOJ 4818 SDOI2017 序列计数