bzoj4818 [Sdoi2017]序列计数
Description
Input
Output
Sample Input
Sample Output
正解:矩阵快速幂/$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]序列计数的更多相关文章
- [BZOJ4818][SDOI2017]序列计数(动规+快速幂)
4818: [Sdoi2017]序列计数 Time Limit: 30 Sec Memory Limit: 128 MBSubmit: 972 Solved: 581[Submit][Status ...
- [bzoj4818][Sdoi2017]序列计数_矩阵乘法_欧拉筛
[Sdoi2017]序列计数 题目大意:https://www.lydsy.com/JudgeOnline/problem.php?id=4818. 题解: 首先列出来一个递推式子 $f[i][0]$ ...
- 2019.02.11 bzoj4818: [Sdoi2017]序列计数(矩阵快速幂优化dp)
传送门 题意简述:问有多少长度为n的序列,序列中的数都是不超过m的正整数,而且这n个数的和是p的倍数,且其中至少有一个数是质数,答案对201704082017040820170408取模(n≤1e9, ...
- BZOJ4818 [SDOI2017]序列计数 【生成函数 + 快速幂】
题目 Alice想要得到一个长度为n的序列,序列中的数都是不超过m的正整数,而且这n个数的和是p的倍数.Alice还希望 ,这n个数中,至少有一个数是质数.Alice想知道,有多少个序列满足她的要求. ...
- BZOJ4818 [SDOI2017] 序列计数 【矩阵快速幂】
题目分析: 一个很显然的同类项合并.注意到p的大小最大为100,考虑把模p意义下相同的求出来最后所有的减去没有质数的做矩阵快速幂即可. 代码: #include<bits/stdc++.h> ...
- 【BZOJ4818】[Sdoi2017]序列计数 DP+矩阵乘法
[BZOJ4818][Sdoi2017]序列计数 Description Alice想要得到一个长度为n的序列,序列中的数都是不超过m的正整数,而且这n个数的和是p的倍数.Alice还希望 ,这n个数 ...
- BZOJ4818 LOJ2002 SDOI2017 序列计数 【矩阵快速幂优化DP】*
BZOJ4818 LOJ2002 SDOI2017 序列计数 Description Alice想要得到一个长度为n的序列,序列中的数都是不超过m的正整数,而且这n个数的和是p的倍数. Alice还希 ...
- [Sdoi2017]序列计数 [矩阵快速幂]
[Sdoi2017]序列计数 题意:长为\(n \le 10^9\)由不超过\(m \le 2 \cdot 10^7\)的正整数构成的和为\(t\le 100\)的倍数且至少有一个质数的序列个数 总- ...
- BZOJ_4818_[Sdoi2017]序列计数_矩阵乘法
BZOJ_4818_[Sdoi2017]序列计数_矩阵乘法 Description Alice想要得到一个长度为n的序列,序列中的数都是不超过m的正整数,而且这n个数的和是p的倍数.Alice还希望 ...
随机推荐
- 深入理解ajax系列第五篇——进度事件
前面的话 一般地,使用readystatechange事件探测HTTP请求的完成.XHR2规范草案定义了进度事件Progress Events规范,XMLHttpRequest对象在请求的不同阶段触发 ...
- Python实现的异步代理爬虫及代理池
使用python asyncio实现了一个异步代理池,根据规则爬取代理网站上的免费代理,在验证其有效后存入redis中,定期扩展代理的数量并检验池中代理的有效性,移除失效的代理.同时用aiohttp实 ...
- 使用git克隆指定分支的代码
今天想学习一下开源中国Android客户端的app源码,源码的Git地址:http://git.oschina.net/oschina/android-app,如下图所示: 由于Master主分支上没 ...
- 部署Cloudera Management for centos 7
hadoop生态圈框架工具甚多,自己整合起来很是繁琐,特别是oozie以及hue结合来实现hive.mr.spark等定时依赖任务更是一步一个坑,为了减少踩坑,只好从apache hadoop,转向C ...
- 混合拉普拉斯分布(LMM)推导及实现
作者:桂. 时间:2017-03-21 07:25:17 链接:http://www.cnblogs.com/xingshansi/p/6592599.html 声明:欢迎被转载,不过记得注明出处哦 ...
- 用PHPExcel类读取excel文件的内容
这里对PHPExcel类不做介绍,有兴趣的朋友可以自己查阅资料 在classes文件夹下有个PHPExcel.php文件,这个文件是这个类库的主要入口文件,在用之前,要引入这个类 其他的类,在此类中会 ...
- centos安装python2.7并安装easy_install,pip,ipython
1.安装python 下载python2.7.10 # wget https://www.python.org/ftp/python/2.7.10/Python-2.7.10.tgz # tar -z ...
- 手动es6编译es5(命令行)
package.json:"devDependencies": { "babel-cli": "^6.18.0", "babel- ...
- linux系统各种乱码问题
linux系统乱码问题 最近使用ubuntu操作系统(客户端)在ssh连接linux服务器的时候发现乱码问题,但是本机查看中文显示中文没有问题,只是在使用终端more查看本地或远端gbk之类中文编码的 ...
- Shell常见用法小记
shell的简单使用 最近发现shell脚本在平常工作中简直算一把瑞士军刀,很多场景下用shell脚本能实现常用的简单需求,而之前都没怎么学习过shell,就趁机把shell相关的语法和常见用法总结了 ...