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

正解:矩阵快速幂/$FFT$+快速幂+中国剩余定理。

昨天晚上考这题,发现是一道$FFT$优化$DP$的裸题。然而数组开小了,所以只有$80$分。。

正解似乎是矩阵快速幂,不过为什么$FFT$跑得快一些。。并且当$p$很大时矩阵快速幂就没用了。。

首先我们可以想到一个$O(n^{3})$的暴力$DP$。设$f[i][j]$表示前$i$个数,模$p$为$j$的方案数,那么$f[i][(j+k) \mod p]+=f[i-1][j]$,其中$k$为枚举选哪个数。

同正解一样,我们求出所有数的情况,然后减去没有质数的情况,最后得到的就是至少有一个质数的情况。

显然,这是一个卷积的形式,那么我们可以考虑用$FFT$来优化$DP$。

首先构造一个模$p$的多项式,$a[i]$表示模$p$为$i$的数有多少个。那么直接用$FFT$和快速幂算出$a^{n}$就行了。

然后线性筛求出所有质数,构造出除去所有质数的多项式$a$,再用一次$FFT$算出$a^{n}$。

第一个多项式的$a[0]$就是模$p$为$0$的情况,第二个多项式的$a[0]$就是没有任何质数且模$p$为$0$的情况,易知两个$a[0]$相减即为答案。

不过这个模数会炸精度,我们把这个模数拆成$8,1091,2311$,分别算出模这$3$个数的答案,最后用中国剩余定理合并就行了。

总复杂度$O(plogplogn)$,所以比矩阵快速幂的$O(p^{3}logn)$要快。不过我没加任何常数优化,所以还是很慢。。

 //It is made by wfj_2048~
#include <algorithm>
#include <iostream>
#include <complex>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#define rhl (20170408)
#define NN (20000010)
#define pi acos(-1.0)
#define inf (1<<30)
#define il inline
#define RG register
#define ll long long
#define C complex <long double>
#define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout) using namespace std; C a[],b[],c[],ans[]; int prime[NN],rev[],r64[],N,n,m,p,lg,cnt;
ll res[],Ans[],ans1,ans2,aans;
bool vis[NN]; il int gi(){
RG int x=,q=; RG char ch=getchar();
while ((ch<'' || ch>'') && ch!='-') ch=getchar();
if (ch=='-') q=-,ch=getchar();
while (ch>='' && ch<='') x=x*+ch-,ch=getchar();
return q*x;
} il void sieve(){
vis[]=;
for (RG int i=;i<=m;++i){
if (!vis[i]) prime[++cnt]=i;
for (RG int j=,k;j<=cnt;++j){
k=i*prime[j]; if (k>m) break;
vis[k]=; if (i%prime[j]==) break;
}
}
return;
} il void FFT(C *a,RG int n,RG int f){
for (RG int i=;i<n;++i)
if (i<rev[i]) swap(a[i],a[rev[i]]);
for (RG int i=;i<n;i<<=){
C wn(cos(pi/i),sin(f*pi/i)),x,y;
for (RG int j=;j<n;j+=(i<<)){
C w(,);
for (RG int k=;k<i;++k,w*=wn){
x=a[j+k],y=w*a[j+k+i];
a[j+k]=x+y,a[j+k+i]=x-y;
}
}
}
return;
} il void mul(C *a,C *b,RG int pp){
for (RG int i=;i<N;++i) c[i]=b[i]; FFT(a,N,),FFT(c,N,);
for (RG int i=;i<N;++i) a[i]*=c[i]; FFT(a,N,-);
memset(res,,sizeof(res));
for (RG int i=;i<N;++i){
res[i%p]+=(ll)(a[i].real()/N+0.5);
res[i%p]%=pp,a[i]=;
}
for (RG int i=;i<p;++i) a[i]=res[i]; return;
} il void qpow(C *a,RG int b,RG int pp){
for (RG int i=;i<N;++i) ans[i]=a[i]; b--;
while (b){ if (b&) mul(ans,a,pp); mul(a,a,pp),b>>=; }
memset(res,,sizeof(res));
for (RG int i=;i<N;++i)
res[i%p]+=(ll)ans[i].real(),res[i%p]%=pp;
return;
} il void exgcd(RG ll a,RG ll b,RG ll &x,RG ll &y){
if (!b){ x=,y=; return; }
exgcd(b,a%b,y,x); y-=(a/b)*x; return;
} il void work(){
n=gi(),m=gi(),p=gi(); for (N=;N<=(p<<);N<<=) lg++;
for (RG int i=;i<N;++i) rev[i]=rev[i>>]>>|((i&)<<(lg-));
r64[]=,r64[]=,r64[]=,sieve();
for (RG int k=;k<=;++k){
memset(a,,sizeof(a)); for (RG int i=;i<=m;++i) a[i%p].real()++;
qpow(a,n,r64[k]); ans1=res[],memset(a,,sizeof(a));
for (RG int i=;i<=m;++i) if (vis[i]) a[i%p].real()++;
qpow(a,n,r64[k]); ans2=res[],Ans[k]=(ans1-ans2+r64[k])%r64[k];
RG ll u=rhl/r64[k],v=r64[k],x=,y=; exgcd(u,v,x,y);
aans+=u*x%rhl*Ans[k],aans%=rhl;
}
printf("%lld",aans); return;
} int main(){
File("count");
work();
return ;
}

bzoj4818 [Sdoi2017]序列计数的更多相关文章

  1. [BZOJ4818][SDOI2017]序列计数(动规+快速幂)

    4818: [Sdoi2017]序列计数 Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 972  Solved: 581[Submit][Status ...

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

    [Sdoi2017]序列计数 题目大意:https://www.lydsy.com/JudgeOnline/problem.php?id=4818. 题解: 首先列出来一个递推式子 $f[i][0]$ ...

  3. 2019.02.11 bzoj4818: [Sdoi2017]序列计数(矩阵快速幂优化dp)

    传送门 题意简述:问有多少长度为n的序列,序列中的数都是不超过m的正整数,而且这n个数的和是p的倍数,且其中至少有一个数是质数,答案对201704082017040820170408取模(n≤1e9, ...

  4. BZOJ4818 [SDOI2017]序列计数 【生成函数 + 快速幂】

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

  5. BZOJ4818 [SDOI2017] 序列计数 【矩阵快速幂】

    题目分析: 一个很显然的同类项合并.注意到p的大小最大为100,考虑把模p意义下相同的求出来最后所有的减去没有质数的做矩阵快速幂即可. 代码: #include<bits/stdc++.h> ...

  6. 【BZOJ4818】[Sdoi2017]序列计数 DP+矩阵乘法

    [BZOJ4818][Sdoi2017]序列计数 Description Alice想要得到一个长度为n的序列,序列中的数都是不超过m的正整数,而且这n个数的和是p的倍数.Alice还希望 ,这n个数 ...

  7. BZOJ4818 LOJ2002 SDOI2017 序列计数 【矩阵快速幂优化DP】*

    BZOJ4818 LOJ2002 SDOI2017 序列计数 Description Alice想要得到一个长度为n的序列,序列中的数都是不超过m的正整数,而且这n个数的和是p的倍数. Alice还希 ...

  8. [Sdoi2017]序列计数 [矩阵快速幂]

    [Sdoi2017]序列计数 题意:长为\(n \le 10^9\)由不超过\(m \le 2 \cdot 10^7\)的正整数构成的和为\(t\le 100\)的倍数且至少有一个质数的序列个数 总- ...

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

    BZOJ_4818_[Sdoi2017]序列计数_矩阵乘法 Description Alice想要得到一个长度为n的序列,序列中的数都是不超过m的正整数,而且这n个数的和是p的倍数.Alice还希望 ...

随机推荐

  1. iOS10构建版本不显示的问题

    iOS10,构建版本问题: 在Xcode中->product->archive,进行相关操作后,upload后没有报错验证也成功的情况下,在开发者账号构建版本号里面迟迟没有显示的原因: i ...

  2. 数据库 sql 表连接

    表链接 分为 横向链接   和纵向链接 横向链接 select * from student,score --笛卡尔积 查询所有表 会出现 笛卡尔积  就是所有匹配的结果都会展示一遍 为防止以上情况 ...

  3. Linux centos7环境下安装Nginx

    Linux centos7环境下安装Nginx的步骤详解 1.    首先到Nginx官网下载Nginx安装包 http://nginx.org/download/nginx-1.5.9.tar.gz ...

  4. mac下安装nginx问题解决

    需要在mac上安装nginx,按照下面的博客链接一步步安装,但是碰到了些问题.下面写一下我的解决方式. (http://stevendu.iteye.com/blog/1535466) 1. 安装PC ...

  5. 卸载php+apache+mysql

    一.卸载删除 mysql   1 sudo apt-get autoremove --purge mysql-server-5.0 2 sudo apt-get remove mysql-server ...

  6. shell 之时间戳

    vim 1.sh #/bin/bash##by cc read -p "Please input yourtime:" timea=$timeif [ $a != 0 ] then ...

  7. Eclipse集成Tomcat教程

    (初学者都会问一个问题,就是Eclipse好用还是Myeclipse好用.好吧,这个问题我昨晚才刚刚问完,哈哈,因为我一开始学Java都是直接下了一个MyeClipse来用的,没想过太多.其实也是,两 ...

  8. Spring中一个类的注入和引用是不一样的

    1.在Spring管理下的bean需要以下面这种方式引入(一种注入方式): private MgrService mgrService; public MgrService getMgrService ...

  9. js的几种简单排序算法及其效率实测

    function swap(arr,index1,index2){ var t = arr[index1]; arr[index1] = arr[index2]; arr[index2] = t; } ...

  10. JDBC(与Oracle的连接)(转)

    JDBC编程步骤:----java与Oracle数据的连接(lomboz_eclipse环境下)  1.在Oracle数据库安装文件夹中找到jdbc文件夹→lib文件夹→classesl2.jar  ...