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还希望 ...
随机推荐
- Solr DateRangeField
Solr DateRangeField 是solr5.0 实现的一个feature. 关于 DateRangeField 支持日期查询如 date_field:[2016-03-23 TO 2017 ...
- JavaScript的基本规范
1.不要在同一行声明多个变量: 2.请使用===/!==来比较true/false或者数值: 3.使用对象字面量替代new Array这种形式: 4.Switch语句必须带有default分支: 5. ...
- 一种抛弃GPS的中近距离高精度无线同步新方案
目前,对于需要做同步数据采集的项目,大家不约而同的选用GPS作同步源,用GPS的秒脉冲作同步基准.对于是1000米内的多采集点的应用来说,这是一种浪费. 目前福州慧聚通信技术有限公司推出一款无线同步数 ...
- unittest单元测试框架实现参数化
当我们在使用TestNG时,发现它有一个非常好用的参数化功能.当你的测试用例有固定的参数和断言结果时,它可以相似用例的节省用例的个数. 例子如下: import static org.testng.A ...
- Cordova框架基本原理
最近在做混编项目,也是从项目里开始接触Cordova框架,网上很多帖子都总结的很好,我还是要总结一下,便于加深一下. Cordova框架是一个可以让JS与原生代码(包括 Android 的 java, ...
- 使用 POJO 对象绑定请求参数
概述 Spring MVC 会按请求参数名和 POJO 属性名进行自动匹配,自动为该对象填充属性值并且支持级联属性.这一特性在日常开发过程中使用频率比较高,开发效率也高,本文主要对 POJO 对象绑定 ...
- 车大棒浅谈jQuery源码(一)
背景 因为最近辞职找工作,投了许多家公司.结果简历要么石沉大海,一点音讯都没有,要么就是邮件回复说不匹配.后面加了一些QQ群,才发现原来我工作经验年限太少了.现在深圳都是3经验起步,北京据说更加恐怖. ...
- MCMC(二)马尔科夫链
MCMC(一)蒙特卡罗方法 MCMC(二)马尔科夫链 MCMC(三)M-H采样和Gibbs采样(待填坑) 在MCMC(一)蒙特卡罗方法中,我们讲到了如何用蒙特卡罗方法来随机模拟求解一些复杂的连续积分或 ...
- win32/mfc/qt 异常处理与总结
际异常一: libcpmtd.lib(xmbtowc.obj) : error LNK2001: unresolved external symbol __CrtDbgReport Debug/B机. ...
- 一个关于Python正则表达式的快速使用手册
一直在纠结自己的博客到底应该写一些什么东西,这几天发现自己的正则用的不是很熟练,于是想要写一篇关于正则表达式的博客,目的就是为了让自己以后要用而又不会的时候不至于像无头苍蝇一样到处乱撞. 有些人在碰到 ...