bzoj 3625: [Codeforces Round #250]小朋友和二叉树【NTT+多项式开根求逆】
参考:https://www.cnblogs.com/2016gdgzoi509/p/8999460.html
列出生成函数方程,g(x)是价值x的个数
\]
+1是f[0]=1
根据公式解出
\]
舍去+的答案,分式上下同乘\( 1-\sqrt{1-4*g(x)} \)
\]
然后套多项式开跟和求逆的板子即可
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int N=500005,mod=998244353,inv2=499122177;
int n,m,bt,lm,re[N],a[N],b[N],c[N],t[N];//,aa[N],bb[N],cc[N];
int read()
{
int r=0,f=1;
char p=getchar();
while(p>'9'||p<'0')
{
if(p=='-')
f=-1;
p=getchar();
}
while(p>='0'&&p<='9')
{
r=r*10+p-48;
p=getchar();
}
return r*f;
}
int ksm(int a,int b)
{
int r=1;
while(b)
{
if(b&1)
r=1ll*r*a%mod;
a=1ll*a*a%mod;
b>>=1;
}
return r;
}
void dft(int a[],int f,int lm)
{
// for(int i=0;i<lm;i++)
// cerr<<a[i]<<" ";cerr<<endl;
// bt=log2(lm);//cerr<<" "<<lm<<" "<<bt<<endl;
// for(int i=0;i<lm;i++)
// re[i]=(re[i>>1]>>1)|((i&1)<<(bt-1));
for(int i=0;i<lm;i++)
if(i<re[i])
swap(a[i],a[re[i]]);
for(int i=1;i<lm;i<<=1)
{
int wi=ksm(3,(mod-1)/(i*2));
if(f==-1)
wi=ksm(wi,mod-2);
for(int k=0;k<lm;k+=(i<<1))
{
int w=1,x,y;
for(int j=0;j<i;j++)
{
x=a[j+k],y=1ll*w*a[i+j+k]%mod;
a[j+k]=(x+y)%mod,a[i+j+k]=(x-y+mod)%mod;
w=1ll*w*wi%mod;
}
}
}
if(f==-1)
{
int ni=ksm(lm,mod-2);
for(int i=0;i<lm;i++)
a[i]=1ll*a[i]*ni%mod;
}
// for(int i=0;i<lm;i++)
// cerr<<a[i]<<" ";cerr<<endl<<endl;;
}
void qiuni(int len)
{
if(len==1)
{
c[0]=ksm(b[0],mod-2);
return;
}
qiuni(len>>1);
memcpy(t,b,sizeof(int)*len);
memset(t+len,0,sizeof(int)*len);
int bt=-1,lm=1;
while(lm<len<<1)
lm<<=1,bt++;
for(int i=0;i<lm;i++)
re[i]=(re[i>>1]>>1)|((i&1)<<bt);
dft(t,1,lm);
dft(c,1,lm);
for(int i=0;i<lm;i++)
c[i]=1ll*c[i]*(2-1ll*t[i]*c[i]%mod+mod)%mod;
dft(c,-1,lm);
memset(c+len,0,sizeof(int)*len);
}
void kaigen(int len)
{
if(len==1)
{
b[0]=1;
return;
}
kaigen(len>>1);
memset(c,0,sizeof(int)*len);
qiuni(len);
memcpy(t,a,sizeof(int)*len);
memset(t+len,0,sizeof(int)*len);
int bt=-1,lm=1;
while(lm<len<<1)
lm<<=1,bt++;
for(int i=0;i<lm;i++)
re[i]=(re[i>>1]>>1)|((i&1)<<bt);
dft(t,1,lm);
dft(b,1,lm);
dft(c,1,lm);
for(int i=0;i<len*2;i++)
b[i]=1ll*(1ll*b[i]*b[i]+t[i])%mod*c[i]%mod*inv2%mod;
dft(b,-1,lm);
memset(b+len,0,sizeof(int)*len);
}
int main()
{
n=read(),m=read();
for(int i=1;i<=n;i++)
{
int x=read();
a[x]++;
}
for(int i=1;i<=m;i++)
a[i]=(-a[i]*4+mod)%mod;
for(bt=1;(1<<bt)<=m;bt++);
lm=(1<<bt);
for(int i=0;i<lm;i++)
if(a[i])
a[i]=mod-4;
a[0]++;
kaigen(lm);
// for(int i=0;i<n;i++)
// cerr<<a[i]<<" "<<b[i]<<" "<<c[i]<<endl;
b[0]=(b[0]+1)%mod;
memset(c,0,sizeof(c));
qiuni(lm);
for(int i=1;i<=m;i++)
printf("%d\n",c[i]*2%mod);
return 0;
}
bzoj 3625: [Codeforces Round #250]小朋友和二叉树【NTT+多项式开根求逆】的更多相关文章
- BZOJ 3625 [Codeforces Round #250]小朋友和二叉树 ——NTT 多项式求逆 多项式开根
生成函数又有奇妙的性质. $F(x)=C(x)*F(x)*F(x)+1$ 然后大力解方程,得到一个带根号的式子. 多项式开根有解只与常数项有关. 发现两个解只有一个是成立的. 然后多项式开根.求逆. ...
- BZOJ 3625: [Codeforces Round #250]小朋友和二叉树
3625: [Codeforces Round #250]小朋友和二叉树 Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 304 Solved: 13 ...
- [BZOJ3625][Codeforces Round #250]小朋友和二叉树 多项式开根+求逆
https://www.lydsy.com/JudgeOnline/problem.php?id=3625 愉快地列式子.设\(F[i]\)表示权值为\(i\) 的子树的方案数,\(A[i]\)为\( ...
- BZOJ3625 [Codeforces Round #250]小朋友和二叉树(生成函数+多项式开根)
设f(n)为权值为n的神犇二叉树个数.考虑如何递推求这个东西. 套路地枚举根节点的左右子树.则f(n)=Σf(i)f(n-i-cj),cj即根的权值.卷积的形式,cj也可以通过卷上一个多项式枚举.可以 ...
- [BZOJ3625][CF438E]小朋友和二叉树 (多项式开根,求逆)
题面 题解 设多项式的第a项为权值和为a的二叉树个数,多项式的第a项表示是否为真,即 则,所以F是三个多项式的卷积,其中包括自己: ,1是F的常数项,即. 我们发现这是一个一元二次方程,可以求出,因为 ...
- BZOJ3625: [Codeforces Round #250]小朋友和二叉树
Description 我们的小朋友很喜欢计算机科学,而且尤其喜欢二叉树.考虑一个含有n个互异正整数的序列c[1],c[2],...,c[n].如果一棵带点权的有根二叉树满足其所有顶点的权值都在集合{ ...
- [Codeforces Round #250]小朋友和二叉树
题目描述: bzoj luogu 题解: 生成函数ntt. 显然这种二叉树应该暴力薅掉树根然后分裂成两棵子树. 所以$f(x)= \sum_{i \in c} \sum _{j=0}^{x-c} f( ...
- [BZOJ 3625] [Codeforces 438E] 小朋友的二叉树 (DP+生成函数+多项式开根+多项式求逆)
[BZOJ 3625] [Codeforces 438E] 小朋友的二叉树 (DP+生成函数+多项式开根+多项式求逆) 题面 一棵二叉树的所有点的点权都是给定的集合中的一个数. 让你求出1到m中所有权 ...
- Codeforces Round #250 (Div. 1)E. The Child and Binary Tree
题意:有一个集合,求有多少形态不同的二叉树满足每个点的权值都属于这个集合并且总点权等于i 题解:先用生成函数搞出来\(f(x)=f(x)^2*c(x)+1\) 然后转化一下变成\(f(x)=\frac ...
随机推荐
- Effective C++ 条款六 若不想使用编译器自动生成的函数,就该明确拒绝
class HomeForSale //防止别人拷贝方法一:将相应的成员函数声明为private并且不予实现 { public: private: HomeForSale(const HomeForS ...
- iOS文件的管理(添加,删除,拷贝,移动)
#import "ViewController.h" @implementation ViewController - (void)viewDidLoad { [super vie ...
- 浅谈JS中的!=、== 、!==、===的用法和区别 JS中Null与Undefined的区别 读取XML文件 获取路径的方式 C#中Cookie,Session,Application的用法与区别? c#反射 抽象工厂
浅谈JS中的!=.== .!==.===的用法和区别 var num = 1; var str = '1'; var test = 1; test == num //tr ...
- 网络请求--Retrofit2用法
欢迎Follow我的GitHub, 关注我的CSDN. Retrofit是Square开发的网络请求库, 简化了网络请求的使用, 这个库太知名了, 优点我就不多说了. 让我们看看怎样使用吧? 注意: ...
- shell学习五十六天----延迟进程调度
延迟进程调度 前言:大部分时候,我们都希望进程快点開始,开点结束,别卡.而shell的运行,也是在前一个命令后,立即接着运行下一个命令.命令完毕的速度是与资源的限制有关,且不在shell的权限下. 在 ...
- android5.0(Lollipop) BLE Peripheral牛刀小试
转载请表明作者:http://blog.csdn.net/lansefeiyang08/article/details/46468743 知道Android L对蓝牙对了一些改进.包含加入A2dp s ...
- MapReduce算法形式二:去重(shuffle)
案例二:去重(shuffle/HashSet等方法)shuffle主要针对的是key去重HashSet主要针对values去重
- 通过反射调用一个单列的方法(单列必须有“getInstance”方法)
Class<?> _clazz = Class.forName(_clazzName); if (_clazz != null) { Method _getInstance = _claz ...
- 使用URL dispatcher的范例
在上面的一篇文章中,我们介绍了怎样使用URL disptacher.在这篇文章中,我们来通过一个范例更进一步来了解怎样实现它. 1)创建一个具有URL dispatcher的应用 我们首先打开我们的S ...
- ruby 学习网站
Ruby on Rails官网: http://rubyonrails.org/ Rails Guides:http://guides.rubyonrails.org/ -中文版: http://gu ...