【UOJ#50】【UR #3】链式反应(分治FFT,动态规划)

题面

UOJ

题解

首先把题目意思捋一捋,大概就是有\(n\)个节点的一棵树,父亲的编号大于儿子。

满足一个点的儿子有\(2+c\)个,其中\(c\in A\),且\(c\)个儿子是叶子,另外\(2\)个存在子树,且两种点的链接的边是不同的,求方案数。

那么就考虑一个暴力\(dp\),设\(f[i]\)表示有\(i\)个节点的树的个数。

那么枚举它两个有子树的子树大小,然后把编号给取出来,得到:

\[f[i]=\frac{1}{2}\sum_{j}\sum_{k} {i-1\choose j}{i-1-j\choose k}f[j]f[k]
\]

其中存在限制,也就是\(i-1-j-k\in A\),要乘\(\frac{1}{2}\)是因为这两个子树选择的时候存在先后关系,所以同一棵子树可能会被计算两次。

这样子我们就可以做\(O(n^3)\)了。

然后把式子给拆一下:

\[{i-1\choose j}{i-1-j\choose k}=\frac{(i-1)!}{j!k!(i-1-j-k)!}
\]

之和\(i,j,k\)相关的可以直接和\(f[i],f[j],f[k]\)丢到一起,剩下的只和\(i/j+k\)相关。

然后预处理\(g[i]=\sum_j \frac{f[j]}{j!}\frac{f[i-j]}{(i-j)!}\)。

那么

\[\frac{2f[i]}{(i-1)!}=\sum_{p=j+k}g[p]*[i-1-p\in A]
\]

这样子就可以做到\(O(n^2)\)了。

进一步发现,\(g\)和\(\frac{2f}{(i-1)!}\)都是卷积的形式,所以可以直接分治\(FFT\)求解做到\(O(nlog^2)\)。

然而这里有细节、、、乱搞会挂。

注意到分治\(FFT\)的过程是\([l,mid]\rightarrow [mid+1,r]\),而\(g\)数组在求解的时候是\(f\)卷上\(f\),这样子会导致乘的数组的范围是\([0,r-l]\),可能存在一部分值没有被计算过。

而这个值具有对称性,所以我们强制\(j<k\)的时候才贡献\(2f[j]*f[k]\)。

也就是如果\(i<l\)的时候,数组里丢进去的是\(2f[i]\),当\(l\le i\le mid\)的时候丢\(f[i]\),否则丢\(0\)进去。

然后两个\(log\)就能过了。

然而这题看起来有更加优秀的做法,但是窝太菜了就不管了。

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define MOD 998244353
#define MAX 840000
int fpow(int a,int b){int s=1;while(b){if(b&1)s=1ll*s*a%MOD;a=1ll*a*a%MOD;b>>=1;}return s;}
int r[MAX],W[MAX];
void NTT(int *P,int opt,int len)
{
int N,l=0;for(N=1;N<len;N<<=1)++l;
for(int i=0;i<N;++i)r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
for(int i=0;i<N;++i)if(i<r[i])swap(P[i],P[r[i]]);
for(int i=1;i<N;i<<=1)
{
int w=fpow(3,(MOD-1)/(i<<1));W[0]=1;
for(int k=1;k<i;++k)W[k]=1ll*W[k-1]*w%MOD;
for(int j=0,p=i<<1;j<N;j+=p)
for(int k=0;k<i;++k)
{
int X=P[j+k],Y=1ll*W[k]*P[i+j+k]%MOD;
P[j+k]=(X+Y)%MOD;P[i+j+k]=(X+MOD-Y)%MOD;
}
}
if(opt==-1)
{
reverse(&P[1],&P[N]);
for(int i=0,inv=fpow(N,MOD-2);i<N;++i)P[i]=1ll*P[i]*inv%MOD;
}
}
int jc[MAX],inv[MAX],jv[MAX];
int f[MAX],g[MAX],A[MAX];
int L[MAX],R[MAX];
void CDQ(int l,int r)
{
if(l==r)
{
if(l==1)f[l]=1;
else f[l]=1ll*f[l]*inv[2]%MOD*jc[l-1]%MOD;
return;
}
int mid=(l+r)>>1,N;
CDQ(l,mid);
for(N=1;N<=mid-l+1+r-l;N<<=1);
for(int i=l;i<=mid;++i)L[i-l]=g[i];
for(int i=0;i<=r-l;++i)R[i]=A[i]*jv[i];
NTT(L,1,N);NTT(R,1,N);
for(int i=0;i<N;++i)L[i]=1ll*L[i]*R[i]%MOD;
NTT(L,-1,N);
for(int i=mid+1;i<=r;++i)f[i]=(f[i]+L[i-1-l])%MOD;
for(int i=0;i<N;++i)L[i]=R[i]=0;
for(int i=l;i<=mid;++i)L[i-l]=1ll*f[i]*jv[i]%MOD;
for(int i=0;i<=r-l;++i)
if(i<l)R[i]=2ll*f[i]*jv[i]%MOD;
else if(i<=mid)R[i]=1ll*f[i]*jv[i]%MOD;
NTT(L,1,N);NTT(R,1,N);
for(int i=0;i<N;++i)L[i]=1ll*L[i]*R[i]%MOD;
NTT(L,-1,N);
for(int i=mid+1;i<=r;++i)g[i]=(g[i]+L[i-l])%MOD;
for(int i=0;i<N;++i)L[i]=R[i]=0; CDQ(mid+1,r);
}
int n;
char ch[MAX];
int main()
{
scanf("%d%s",&n,ch);
for(int i=0;i<n;++i)A[i]=ch[i]-48;
jc[0]=jv[0]=inv[0]=inv[1]=1;
for(int i=2;i<=n;++i)inv[i]=1ll*inv[MOD%i]*(MOD-MOD/i)%MOD;
for(int i=1;i<=n;++i)jc[i]=1ll*jc[i-1]*i%MOD;
for(int i=1;i<=n;++i)jv[i]=1ll*jv[i-1]*inv[i]%MOD;
f[1]=1;
/*
for(int i=2;i<=n;++i)
{
for(int j=0;j<=i;++j)g[i]=(g[i]+1ll*f[j]*jv[j]%MOD*f[i-j]%MOD*jv[i-j]%MOD)%MOD;
for(int j=0;j<i;++j)
if(A[i-1-j])
f[i]=(f[i]+1ll*g[j]*jv[i-1-j])%MOD;
f[i]=1ll*f[i]*inv[2]%MOD*jc[i-1]%MOD;
}
*/
CDQ(1,n);
for(int i=1;i<=n;++i)printf("%d\n",f[i]);
return 0;
}

【UOJ#50】【UR #3】链式反应(分治FFT,动态规划)的更多相关文章

  1. 【LOJ#575】【LNR#2】不等关系(容斥,动态规划,分治FFT)

    [LOJ#575][LNR#2]不等关系(容斥,动态规划,分治FFT) 题面 LOJ 题解 一个暴力\(dp\),设\(f[i][j]\)表示考虑完了前\(i\)个位置,其中最后一个数在前面所有数中排 ...

  2. 【UOJ#76】【UR #6】懒癌(动态规划)

    [UOJ#76][UR #6]懒癌(动态规划) 题面 UOJ 题解 神....神仙题. 先考虑如果是完全图怎么做... 因为是完全图,所以是对称的,所以我们只考虑一个有懒癌的人的心路历程. 如果只有一 ...

  3. 【UOJ#22】【UR #1】外星人(动态规划)

    [UOJ#22][UR #1]外星人(动态规划) 题面 UOJ 题解 一道简单题? 不难发现只有按照从大往小排序的顺序选择的才有意义,否则先选择一个小数再去模一个大数是没有意义的. 设\(f[i][j ...

  4. uoj#401. 【CTSC2018】青蕈领主(分治FFT)

    传送门 话说分治\(FFT\)是个啥子啊--还有题目里那字好像念(蕈xùn) 首先考虑无解的情况:区间相交或者\(L_n\neq n\) 这两个都可以感性理解一下 所以区间之间只会有包含关系,我们把每 ...

  5. UOJ#401. 【CTSC2018】青蕈领主 分治,FFT

    原文链接www.cnblogs.com/zhouzhendong/p/UOJ401.html 题解 首先,对于一个排列,它的连续段一定只有包含关系,没有相交关系. 我们可以据此得到一棵表示连续段的树. ...

  6. 再探快速傅里叶变换(FFT)学习笔记(其三)(循环卷积的Bluestein算法+分治FFT+FFT的优化+任意模数NTT)

    再探快速傅里叶变换(FFT)学习笔记(其三)(循环卷积的Bluestein算法+分治FFT+FFT的优化+任意模数NTT) 目录 再探快速傅里叶变换(FFT)学习笔记(其三)(循环卷积的Blueste ...

  7. [Codeforces 553E]Kyoya and Train(期望DP+Floyd+分治FFT)

    [Codeforces 553E]Kyoya and Train(期望DP+Floyd+分治FFT) 题面 给出一个\(n\)个点\(m\)条边的有向图(可能有环),走每条边需要支付一个价格\(c_i ...

  8. BNUOJ 51279[组队活动 Large](cdq分治+FFT)

    传送门 大意:ACM校队一共有n名队员,从1到n标号,现在n名队员要组成若干支队伍,每支队伍至多有m名队员,求一共有多少种不同的组队方案.两个组队方案被视为不同的,当且仅当存在至少一名队员在两种方案中 ...

  9. hdu 5730 Shell Necklace [分治fft | 多项式求逆]

    hdu 5730 Shell Necklace 题意:求递推式\(f_n = \sum_{i=1}^n a_i f_{n-i}\),模313 多么优秀的模板题 可以用分治fft,也可以多项式求逆 分治 ...

随机推荐

  1. RubyMine生成reader/writer方法

    RubyMine生成reader/writer方法 在非类的ruby文件中,Alt+Insert会出现新建文件的选项: 在ruby文件的类中,Alt+Insert会出现get/set方法生成提示和重构 ...

  2. 好纠结啊,JeeWx商业版本号和开源版本号有什么差别呢?

    好纠结啊,JeeWx商业版本号和开源版本号有什么差别呢? JeeWx开源版本号是一套基础微信开发平台.有基础的微信菜单.素材管理.微信对接等基础功能,适合于开发人员学习研究. JeeWx商业版本号是一 ...

  3. cocos2d函数

    CCNodeLoader::parseProperties CCBReader::readNodeGraph kCCBPropTypeBlockCCControl CCInvocation parse ...

  4. 【转】selenium自动化测试环境搭建

    转:http://blog.csdn.net/mao1059568684/article/details/17347853 第一步 安装JDK JDk1.7. 下载地址:http://www.orac ...

  5. Eclipse开启代码自动提示功能

    Eclipse代码里面的代码提示功能默认是关闭的,只有输入“.”的时候才会提示功能,用vs的用户可能不太习惯 这种,vs是输入任何字母都会提示,下面说一下如何修改eclipse配置,开启代码自动提示功 ...

  6. raspberry-常用命令

    安全关闭raspberry:sudo shutdown -h now 一次升级系统中的所有内容:sudo apt-get update 升级单个软件包:sudo apt-get install *** ...

  7. php gd

    imagecopy() 函数用于拷贝图像或图像的一部分. imagecopyresized() 函数用于拷贝部分图像并调整大小. imagecopy() imagecopy() 函数用于拷贝图像或图像 ...

  8. 基于mkdocs-material搭建个人静态博客

    基于mkdocs-material搭建个人纯静态博客,没有php,没有mysql 如果你只是想安安静静的放一些技术文章,发布到个人站点或github-pages,mkdocs-material很适合你 ...

  9. 跨域解决方案之JSONP,通过借助调用百度搜索的API了解跨域案例

    跨域解决方案之JSONP 同源策略 同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响.可以说Web ...

  10. java8-1-interface接口

    Java 8 允许我们使用default关键字,为接口声明添加非抽象的方法实现.这个特性又被称为扩展方法 sample: interface Formula { double calculate(in ...