HDU.5730.Shell Necklace(分治FFT)
\(Description\)
有\(n\)个长度分别为\(1,2,\ldots,n\)的珠子串,每个有\(a_i\)种,每种个数不限。求有多少种方法组成长度为\(n\)的串。答案对\(313\)取模。
\(Solution\)
令\(f_i\)表示组成长度为\(i\)的串的方案数,可以得到递推式:$$f_i=\sum_{j=0}^{i-1}a_{i-j}f_j,\ f_0=1$$或者\(f_i=\sum_{j=1}^{i-1}a_{i-j}f_j+a_i\)。
这样暴力是\(O(n^2)\)的。
因为运算的形式是卷积,可以用\(FFT\)代替,这样复杂度是\(O(n^2\log n)\)。再套用CDQ分治就可以\(O(n\log^2 n)\)了。
在分治过程中,先计算出\(j\in [l,mid]\)的\(f_j\),与\(a\)做卷积,就可以得到区间\([l,mid]\)对\(f_i,\ i\in[mid+1,r]\)的贡献。即$$f_{i,i\in[mid+1,r]}+=\sum_{j=l}^{mid}a_{i-j}f_j$$
\(a_{1\sim r-l}\)与\(f_{l\sim mid}\)卷积后得到的多项式的第\(mid+i-l\)项(下标的话要-1),就是对\(f_{mid+i}\)的贡献。
(\(a_{1,r-l}*f_{l,m}\)的下标\(0\)项为\(l+1\),那\(mid+i\)的下标就是\(mid+i-l-1\))
因为只更新到\(a_r\),它是由\(f_{r-l-1}\)转移来的,所以每次FFT的\(lim\)只需大于\(r-l\)即可。优化明显(670MS 11496K -> 327MS 6904K)。
注:这个项是从\(0\)编号的,如果把\(a_0=0\)这一项一起卷积,原第\(mid-l+i\)项的下标就是\(mid-l+i\)了(没啥用吧,但是网上的都这么写,理解了半天为啥要加上\(a_0\),写完代码才明白。。)
对卷积理解不够啊。
看了看网上题解感觉也没多少说清楚的,代码跑的还慢→_→
//327MS 6904K
#include <cmath>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
//#define gc() getchar()
#define MAXIN 300000
#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
#define mod (313)
const double PI=acos(-1);
const int N=1e5+5,M=(1<<18)+1;//262144
int n,a[N],rev[M],f[N];
char IN[MAXIN],*SS=IN,*TT=IN;
struct Complex
{
double x,y;
Complex() {}
Complex(double x,double y):x(x),y(y) {}
Complex operator +(const Complex &a) {return Complex(x+a.x, y+a.y);}
Complex operator -(const Complex &a) {return Complex(x-a.x, y-a.y);}
Complex operator *(const Complex &a) {return Complex(x*a.x-y*a.y, x*a.y+y*a.x);}
}A[M],B[M];
inline int read()
{
int now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now;
}
void FFT(Complex *a,int lim,int opt)
{
for(int i=1; i<lim; ++i) if(i<rev[i]) std::swap(a[i],a[rev[i]]);
for(int i=2; i<=lim; i<<=1)
{
int mid=i>>1;
Complex Wn(cos(PI/mid),opt*sin(PI/mid)),t;//Wn(cos(2.0*PI/i),opt*sin(2.0*PI/i)),t;
for(int j=0; j<lim; j+=i)
{
Complex w(1,0);
for(int k=0; k<mid; ++k,w=w*Wn)
a[j+mid+k]=a[j+k]-(t=a[j+mid+k]*w),
a[j+k]=a[j+k]+t;
}
}
if(opt==-1) for(int i=0; i<lim; ++i) a[i].x/=lim;
}
void Calc(int *a,int len1,int *b,int len2)
{
int lim=1, L=-1;
while(lim<=len1) lim<<=1, ++L;
for(int i=1; i<lim; ++i) rev[i]=(rev[i>>1]>>1)|((i&1)<<L);
for(int i=0; i<len1; ++i) A[i]=Complex(a[i],0);
for(int i=len1; i<lim; ++i) A[i]=Complex(0,0);
for(int i=0; i<len2; ++i) B[i]=Complex(b[i],0);
for(int i=len2; i<lim; ++i) B[i]=Complex(0,0);
FFT(A,lim,1), FFT(B,lim,1);
for(int i=0; i<lim; ++i) A[i]=A[i]*B[i];
FFT(A,lim,-1);
}
void CDQ(int l,int r)
{
if(l==r) return;
int mid=l+r>>1;
CDQ(l,mid);
Calc(a+1,r-l,f+l,mid-l+1);
for(int i=mid+1; i<=r; ++i) (f[i]+=((long long)(A[i-l-1].x+0.5)%mod))%=mod;//mid+1-l -> mid+1
// Calc(a,r-l+1,f+l,mid-l+1);//算上a_0=0这一项 A[]的下标就不用-1了。。
// for(int i=mid+1; i<=r; ++i) (f[i]+=((long long)(A[i-l].x+0.5)%mod))%=mod;//mid+1-l -> mid+1
// for(int i=mid-l+1; i<=r-l; ++i) (f[l+i]+=((long long)(A[i].x+0.5)%mod))%=mod;//longlong!
// mid+i <= r -> i <= mid-l+r-mid = r-l ?
CDQ(mid+1,r);
}
int main()
{
while(n=read())
{
memset(f,0,sizeof f);
for(int i=1; i<=n; ++i) a[i]=read()%mod;
f[0]=1, CDQ(0,n), printf("%d\n",f[n]);
}
return 0;
}
HDU.5730.Shell Necklace(分治FFT)的更多相关文章
- hdu 5730 Shell Necklace [分治fft | 多项式求逆]
hdu 5730 Shell Necklace 题意:求递推式\(f_n = \sum_{i=1}^n a_i f_{n-i}\),模313 多么优秀的模板题 可以用分治fft,也可以多项式求逆 分治 ...
- hdu 5730 Shell Necklace —— 分治FFT
题目:http://acm.hdu.edu.cn/showproblem.php?pid=5730 DP式:\( f[i] = \sum\limits_{j=1}^{i} f[i-j] * a[j] ...
- hdu 5730 Shell Necklace——多项式求逆+拆系数FFT
题目:http://acm.hdu.edu.cn/showproblem.php?pid=5730 可以用分治FFT.但自己只写了多项式求逆. 和COGS2259几乎很像.设A(x),指数是长度,系数 ...
- HDU 5730 Shell Necklace(CDQ分治+FFT)
[题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=5730 [题目大意] 给出一个数组w,表示不同长度的字段的权值,比如w[3]=5表示如果字段长度为3 ...
- HDU 5730 Shell Necklace cdq分治+FFT
题意:一段长为 i 的项链有 a[i] 种装饰方式,问长度为n的相连共有多少种装饰方式 分析:采用dp做法,dp[i]=∑dp[j]*a[i-j]+a[i],(1<=j<=i-1) 然后对 ...
- hdu 5730 Shell Necklace fft+cdq分治
题目链接 dp[n] = sigma(a[i]*dp[n-i]), 给出a1.....an, 求dp[n]. n为1e5. 这个式子的形式显然是一个卷积, 所以可以用fft来优化一下, 但是这样也是会 ...
- #8 //HDU 5730 Shell Necklace(CDQ分治+FFT)
Description 给出长度分别为1~n的珠子,长度为i的珠子有a[i]种,每种珠子有无限个,问用这些珠子串成长度为n的链有多少种方案 题解: dp[i]表示组合成包含i个贝壳的项链的总方案数 转 ...
- HDU 5730 - Shell Necklace
题意: 给出连续的1-n个珠子的涂色方法 a[i](1<=i<=n), 问长度为n的珠链共有多少种涂色方案 分析: 可以得到DP方程: DP[n] = ∑(i=1,n) (DP[n-i]* ...
- hdu Shell Necklace 5730 分治FFT
Description Perhaps the sea‘s definition of a shell is the pearl. However, in my view, a shell neckl ...
随机推荐
- Hadoop基础-MapReduce的Join操作
Hadoop基础-MapReduce的Join操作 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.连接操作Map端Join(适合处理小表+大表的情况) no001 no002 ...
- linux常用端口查询
0 | 无效端口,通常用于分析操作系统1 | 传输控制协议端口服务多路开关选择器2 | 管理实用程序3 | 压缩进程5 | 远程作业登录7 | 回显9 | 丢弃11 | 在线用户13 | 时间17 | ...
- SQL中的全局变量和局部变量(@@/@)
在SQL中,我们常常使用临时表来存储临时结果,对于结果是一个集合的情况,这种方法非常实用,但当结果仅仅是一个数据或者是几个数据时,还要去建一个表,显得就比较麻烦,另外,当一个SQL语句中的某些元素经常 ...
- 【原创】when.js2.7.1源码解析
现在,用回调处理一些复杂的逻辑,显得代码臃肿,难于阅读,特别是异步,嵌套. 解决这样的问题,可以是之前所说的Backbone.Events的pubsub,或者是今天要说的when.js所实现的prom ...
- 第10月第13天 xcode ipa
1. xcodebuild -exportArchive -exportFormat ipa -archivePath RongChatRoomDemo\ 17-7-13\ 下午4.04.xcarch ...
- Javascript - Vue - 过滤器
过滤器 输出的数据由vue对象提供,但它的数据可能需要做进一步的处理才适合展示给用户看,为此,可以在静态的Vue上定义一个过滤器对实例vue对象的data数据进行过滤处理. //调用过滤器//msg是 ...
- 采用jacob实现word转pdf
网络上已经有很多这方面的内容,在用之前也是参考了好多别人的文章,下面记录下我自己的整合过程.整个过程都比较简单: 开发环境:win8 64位系统,在2008下面部署也是一样的. 文档要求jdk的版本要 ...
- 【Pyhon】获取文件MIME类型,根据文件类型自定义文件后缀
场景 下载样本,都是MD5命名的无后缀文件,需要自己手动查询然后修改文件后缀. 根据文件类型自定义后缀可以很方便地根据后缀判断用什么工具分析. 使用说明 libmagic 地址:https://pyp ...
- Regular Expression Matching & Wildcard Matching
Regular Expression Matching Implement regular expression matching with support for '.' and '*'. '.' ...
- 修改history记录数门限
你的 Bash 命令历史保存的历史命令的数量可以在 ~/.bashrc 文件里设置.在这个文件里,你可以找到下面两行: HISTSIZE=1000 HISTFILESIZE=2000 HISTSIZE ...