参考:https://www.cnblogs.com/2016gdgzoi509/p/8999460.html

列出生成函数方程,g(x)是价值x的个数

\[f(x)=g(x)*f^2(x)+1
\]

+1是f[0]=1

根据公式解出

\[f(x)=\frac{1+(-)\sqrt{1-4*g(x)}}{2*g(x)}
\]

舍去+的答案,分式上下同乘\( 1-\sqrt{1-4*g(x)} \)

\[f(x)=\frac{2}{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+多项式开根求逆】的更多相关文章

  1. BZOJ 3625 [Codeforces Round #250]小朋友和二叉树 ——NTT 多项式求逆 多项式开根

    生成函数又有奇妙的性质. $F(x)=C(x)*F(x)*F(x)+1$ 然后大力解方程,得到一个带根号的式子. 多项式开根有解只与常数项有关. 发现两个解只有一个是成立的. 然后多项式开根.求逆. ...

  2. BZOJ 3625: [Codeforces Round #250]小朋友和二叉树

    3625: [Codeforces Round #250]小朋友和二叉树 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 304  Solved: 13 ...

  3. [BZOJ3625][Codeforces Round #250]小朋友和二叉树 多项式开根+求逆

    https://www.lydsy.com/JudgeOnline/problem.php?id=3625 愉快地列式子.设\(F[i]\)表示权值为\(i\) 的子树的方案数,\(A[i]\)为\( ...

  4. BZOJ3625 [Codeforces Round #250]小朋友和二叉树(生成函数+多项式开根)

    设f(n)为权值为n的神犇二叉树个数.考虑如何递推求这个东西. 套路地枚举根节点的左右子树.则f(n)=Σf(i)f(n-i-cj),cj即根的权值.卷积的形式,cj也可以通过卷上一个多项式枚举.可以 ...

  5. [BZOJ3625][CF438E]小朋友和二叉树 (多项式开根,求逆)

    题面 题解 设多项式的第a项为权值和为a的二叉树个数,多项式的第a项表示是否为真,即 则,所以F是三个多项式的卷积,其中包括自己: ,1是F的常数项,即. 我们发现这是一个一元二次方程,可以求出,因为 ...

  6. BZOJ3625: [Codeforces Round #250]小朋友和二叉树

    Description 我们的小朋友很喜欢计算机科学,而且尤其喜欢二叉树.考虑一个含有n个互异正整数的序列c[1],c[2],...,c[n].如果一棵带点权的有根二叉树满足其所有顶点的权值都在集合{ ...

  7. [Codeforces Round #250]小朋友和二叉树

    题目描述: bzoj luogu 题解: 生成函数ntt. 显然这种二叉树应该暴力薅掉树根然后分裂成两棵子树. 所以$f(x)= \sum_{i \in c} \sum _{j=0}^{x-c} f( ...

  8. [BZOJ 3625] [Codeforces 438E] 小朋友的二叉树 (DP+生成函数+多项式开根+多项式求逆)

    [BZOJ 3625] [Codeforces 438E] 小朋友的二叉树 (DP+生成函数+多项式开根+多项式求逆) 题面 一棵二叉树的所有点的点权都是给定的集合中的一个数. 让你求出1到m中所有权 ...

  9. Codeforces Round #250 (Div. 1)E. The Child and Binary Tree

    题意:有一个集合,求有多少形态不同的二叉树满足每个点的权值都属于这个集合并且总点权等于i 题解:先用生成函数搞出来\(f(x)=f(x)^2*c(x)+1\) 然后转化一下变成\(f(x)=\frac ...

随机推荐

  1. sort-list——链表、快慢指针找中间、归并排序

    Sort a linked list in O(n log n) time using constant space complexity. 链表,快慢指针找中点,归并排序. 注意判断条件fast-& ...

  2. BZOJ 3363 POJ 1985 Cow Marathon 树的直径

    题目大意:给出一棵树.求两点间的最长距离. 思路:裸地树的直径.两次BFS,第一次随便找一个点宽搜.然后用上次宽搜时最远的点在宽搜.得到的最长距离就是树的直径. CODE: #include < ...

  3. VC中常见API函数使用方法(经验版)

    ***********************************************声明*************************************************** ...

  4. mysql 存储过程(支持事务管理)

    CREATE DEFINER=`root`@`localhost` PROCEDURE `createBusiness`(parameter1 int) BEGIN #Routine body goe ...

  5. requirejs中的define

    关于requirejs中的define的原理理解   我们已经了解到模块模式是为单例创建私有变量和特权方法的.一个最基本的例子: var foo=(function(){ var something= ...

  6. 第04章-VTK基础(2)

    [译者:这个系列教程是以Kitware公司出版的<VTK User's Guide -11th edition>一书作的中文翻译(出版时间2010年,ISBN: 978-1-930934- ...

  7. 基于redis集群实现的分布式锁,可用于秒杀商品的库存数量管理,有測试代码(何志雄)

    转载请标明出处. 在分布式系统中,常常会出现须要竞争同一资源的情况,本代码基于redis3.0.1+jedis2.7.1实现了分布式锁. redis集群的搭建,请见我的另外一篇文章:<>& ...

  8. Java核心技术之基本数据类型

    这篇文章.我们讨论一些java的最主要的东西.这些东西我们一般刚刚学java的时候就学过,可是不一定真正明确. 正好,我在做一个读取内存的值,涉及到bit位的值的读取和写.那就能够讨论一个java的基 ...

  9. Xamarin Android 记事本(三)删改

    这篇我就不做太多的说明了,数据操作之前也都举过例子了,这里就直接贴出删除和修改的代码. public override bool OnOptionsItemSelected(IMenuItem ite ...

  10. gRPC错误码 http状态码 provide your APIs in both gRPC and RESTful style at the same time

    How gRPC error codes map to HTTP status codes in the response https://github.com/grpc-ecosystem/grpc ...