Codeforces 438E. The Child and Binary Tree 多项式,FFT
原文链接www.cnblogs.com/zhouzhendong/p/CF438E.html
前言
没做过多项式题,来一道入门题试试刀。
题解
设 $a_i$ 表示节点权值和为 $i$ 的二叉树个数,特别的,我们定义 $a_0 = 1$ ,即我们认为没有节点也算一种二叉树。
设
$$g(x) = \sum_{i=1}^n x^{c_i}\\f(x) = \sum_{i=0}^{\infty} a_i x^i$$
根据组合意义可得
$$f^2(x) g(x) + 1 = f(x) $$
于是
$$f^2(x) g(x) - f(x) + 1 = 0$$
注意到 $g(0) = 0$ ,所以当 $x = 0$ 时, $f(x) = 1$ 。
直接用求根公式得到
$$f(x) = \frac{1 \pm \sqrt{1 - 4g(x)}}{2g(x)}$$
由于 $g(0) = 0$ ,所以 $g(x)$ 不存在逆元,所以 $g(x)$ 在分母上会不舒服,于是我们对式子操作一波:
$$f(x) = \frac{1 - (1 - 4g(x))}{2g(x) (1\pm \sqrt{1-4g(x)})}\\ = \frac 2 {1 \pm \sqrt {1-4g(x)}}$$
接下来我们看看这个 $\pm$ 到底应该是正的还是负的。
由于 $f(0) = 1$ ,所以 $\frac{2}{1\pm\sqrt{1-4g(0)}} = 1$ ,于是得到这里为正号。
于是
$$\frac 2 {1+\sqrt {1-4g(x)}}$$
于是用多项式求逆和多项式开根即可解决此问题。
时间复杂度 $O(m\log m)$ 。
代码
#include <bits/stdc++.h>
#define clr(x) memset(x,0,sizeof (x))
#define clrint(x,n) memset(x,0,(n)<<2)
#define cpyint(a,b,n) memcpy(a,b,(n)<<2)
#define For(i,a,b) for (int i=a;i<=b;i++)
#define Fod(i,b,a) for (int i=b;i>=a;i--)
#define pb(x) push_back(x)
#define mp(x,y) make_pair(x,y)
#define fi first
#define se second
#define real __zzd001
#define _SEED_ ('C'+'L'+'Y'+'A'+'K'+'I'+'O'+'I')
#define outval(x) printf(#x" = %d\n",x)
#define outvec(x) printf("vec "#x" = ");for (auto _v : x)printf("%d ",_v);puts("")
#define outtag(x) puts("----------"#x"----------")
#define outarr(a,L,R) printf(#a"[%d...%d] = ",L,R);\
For(_v2,L,R)printf("%d ",a[_v2]);puts("");
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef vector <int> vi;
LL read(){
LL x=0,f=0;
char ch=getchar();
while (!isdigit(ch))
f|=ch=='-',ch=getchar();
while (isdigit(ch))
x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return f?-x:x;
}
const int N=1<<19,mod=998244353,inv2=(mod+1)>>1;
const int YG=3;
int Pow(int x,int y){
int ans=1;
for (;y;y>>=1,x=(LL)x*x%mod)
if (y&1)
ans=(LL)ans*x%mod;
return ans;
}
void Add(int &x,int y){
if ((x+=y)>=mod)
x-=mod;
}
void Del(int &x,int y){
if ((x-=y)<0)
x+=mod;
}
int Add(int x){
return x>=mod?x-mod:x;
}
int Del(int x){
return x<0?x+mod:x;
}
namespace Math{
int Iv[N];
void prework(){
int n=N-1;
Iv[1]=1;
For(i,2,n)
Iv[i]=(LL)(mod-mod/i)*Iv[mod%i]%mod;
}
map <int,int> Map;
int ind(int x){
static int M,bas;
if (Map.empty()){
M=max((int)sqrt(mod),1);
bas=Pow(YG,M);
for (int i=1,v=YG;i<=M;i++,v=(LL)v*YG%mod)
Map[v]=i;
}
for (int i=M,v=(LL)bas*Pow(x,mod-2)%mod;i<=mod-1+M;i+=M,v=(LL)v*bas%mod)
if (Map[v])
return i-Map[v];
return -1;
}
}
namespace fft{
int w[N],R[N];
int Log[N+1];
void init(int n){
if (!Log[2]){
For(i,2,N)
Log[i]=Log[i>>1]+1;
}
int d=Log[n];
assert(n==(1<<d));
For(i,0,n-1)
R[i]=(R[i>>1]>>1)|((i&1)<<(d-1));
w[0]=1,w[1]=Pow(YG,(mod-1)/n);
For(i,2,n-1)
w[i]=(LL)w[i-1]*w[1]%mod;
}
void FFT(int *a,int n,int flag){
if (flag<0)
reverse(w+1,w+n);
For(i,0,n-1)
if (i<R[i])
swap(a[i],a[R[i]]);
for (int t=n>>1,d=1;d<n;d<<=1,t>>=1)
for (int i=0;i<n;i+=d<<1)
for (int j=0;j<d;j++){
int tmp=(LL)w[t*j]*a[i+j+d]%mod;
a[i+j+d]=Del(a[i+j]-tmp);
Add(a[i+j],tmp);
}
if (flag<0){
reverse(w+1,w+n);
int inv=Pow(n,mod-2);
For(i,0,n-1)
a[i]=(LL)a[i]*inv%mod;
}
}
void CirMul(int *a,int *b,int *c,int n){
init(n),FFT(a,n,1),FFT(b,n,1);
For(i,0,n-1)
c[i]=(LL)a[i]*b[i]%mod;
FFT(c,n,-1);
}
}
using fft::FFT;
using fft::CirMul;
int calc_up(int x){
int n=1;
while (n<=x)
n<<=1;
return n;
}
void Inv(int *a,int *b,int n){
static int f[N],g[N];
b[0]=Pow(a[0],mod-2);
int now=1;
while (now<n){
int len=now<<2;
For(i,0,len-1)
f[i]=g[i]=0;
cpyint(g,b,now),now<<=1,cpyint(f,a,min(n,now));
fft::init(len);
FFT(f,len,1),FFT(g,len,1);
For(i,0,len-1)
g[i]=(2LL*g[i]-(LL)f[i]*g[i]%mod*g[i]%mod+mod)%mod;
FFT(g,len,-1);
cpyint(b,g,min(n,now));
}
}
int Sqrt(int a){
int k=Math::ind(a);
assert(~k&1);
k=Pow(YG,k>>1);
return min(k,mod-k);
}
void Sqrt(int *a,int *b,int n){
static int f[N],g[N],h[N];
b[0]=Sqrt(a[0]);
int now=1;
while (now<n){
int len=now<<2;
For(i,0,len-1)
f[i]=g[i]=h[i]=0;
cpyint(f,b,now),now<<=1,Inv(f,h,now),cpyint(g,a,min(n,now));
CirMul(g,h,g,len);
For(i,0,len-1)
f[i]=((g[i]+f[i])&1)?Add(((LL)g[i]+f[i]+mod)>>1):((g[i]+f[i])>>1);
cpyint(b,f,min(n,now));
}
}
void Der(int *a,int n){
For(i,0,n-2)
a[i]=(LL)a[i+1]*(i+1)%mod;
a[n-1]=0;
}
void Int(int *a,int n){
if (!Math::Iv[1])
Math::prework();
Fod(i,n,1)
a[i]=(LL)a[i-1]*Math::Iv[i]%mod;
a[0]=0;
}
void Ln(int *a,int *b,int n){
static int f[N],g[N];
int len=calc_up(n*2);
For(i,0,len-1)
f[i]=g[i]=0;
cpyint(f,a,n),Inv(f,g,n),Der(f,n);
CirMul(f,g,f,len);
Int(f,n),cpyint(b,f,n);
}
void Exp(int *a,int *b,int n){
static int f[N],g[N],h[N];
b[0]=1;
int now=1;
while (now<n){
int len=now<<2;
For(i,0,len-1)
f[i]=g[i]=h[i]=0;
cpyint(f,b,now),now<<=1,Ln(f,g,now),cpyint(h,a,min(n,now));
For(i,0,now-1)
g[i]=Del(h[i]-g[i]);
Add(g[0],1);
CirMul(f,g,f,len),cpyint(b,f,min(n,now));
}
}
void Pow(int *a,int *b,int n,int k){
static int f[N];
clrint(b,n);
if (k==0)
return (void)(b[0]=1);
int fir=0;
for (;fir<n&&!a[fir];fir++);
if ((LL)fir*k>=n)
return;
int m=n-fir*k;
cpyint(f,a+fir,m);
int t=Pow(f[0],k),it=Pow(f[0],mod-2);
For(i,0,m-1)
f[i]=(LL)f[i]*it%mod;
Ln(f,f,m);
For(i,0,m-1)
f[i]=(LL)f[i]*k%mod;
Exp(f,b+fir*k,m);
For(i,fir*k,n-1)
b[i]=(LL)b[i]*t%mod;
}
int n,m;
int f[N],g[N];
int main(){
n=read(),m=read()+1;
while (n--)
g[read()]=mod-4;
Add(g[0],1);
Sqrt(g,f,m);
Add(f[0],1);
Inv(f,g,m);
For(i,1,m-1)
printf("%d\n",g[i]=g[i]*2%mod);
return 0;
}
Codeforces 438E. The Child and Binary Tree 多项式,FFT的更多相关文章
- Codeforces 438E The Child and Binary Tree - 生成函数 - 多项式
题目传送门 传送点I 传送点II 传送点III 题目大意 每个点的权值$c\in {c_{1}, c_{2}, \cdots, c_{n}}$,问对于每个$1\leqslant s\leqslant ...
- Codeforces 438E The Child and Binary Tree [DP,生成函数,NTT]
洛谷 Codeforces 思路 看到计数和\(998244353\),可以感觉到这是一个DP+生成函数+NTT的题. 设\(s_i\)表示\(i\)是否在集合中,\(A\)为\(s\)的生成函数,即 ...
- bzoj 3625(CF 438E)The Child and Binary Tree——多项式开方
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3625 http://codeforces.com/contest/438/problem/E ...
- Codeforces 250 E. The Child and Binary Tree [多项式开根 生成函数]
CF Round250 E. The Child and Binary Tree 题意:n种权值集合C, 求点权值和为1...m的二叉树的个数, 形态不同的二叉树不同. 也就是说:不带标号,孩子有序 ...
- 【CF】438E. The Child and Binary Tree
http://codeforces.com/contest/438/problem/E 题意:询问每个点权值在 $c_1, c_2, ..., c_m$ 中,总权值和为 $s$ 的二叉树个数.请给出每 ...
- CF 438E The Child and Binary Tree
BZOJ 3625 吐槽 BZOJ上至今没有卡过去,太慢了卡得我不敢交了…… 一件很奇怪的事情就是不管是本地还是自己上传数据到OJ测试都远远没有到达时限. 本题做法 设$f_i$表示权值为$i$的二叉 ...
- 【CF438E】The Child and Binary Tree(多项式运算,生成函数)
[CF438E]The Child and Binary Tree(多项式运算,生成函数) 题面 有一个大小为\(n\)的集合\(S\) 问所有点权都在集合中,并且点权之和分别为\([0,m]\)的二 ...
- [codeforces438E]The Child and Binary Tree
[codeforces438E]The Child and Binary Tree 试题描述 Our child likes computer science very much, especiall ...
- [题解] CF438E The Child and Binary Tree
CF438E The Child and Binary Tree Description 给一个大小为\(n\)的序列\(C\),保证\(C\)中每个元素各不相同,现在你要统计点权全在\(C\)中,且 ...
随机推荐
- C语言博客作业06——结构体&文件
C语言博客作业06--结构体&文件 1.本章学习总结 1.1思维导图 1.2.本章学习体会 在本周的学习中,我们学习了关于结构体和文件的内容.结构体的本身并不难,但以结构体为基础的链表还是让我 ...
- Python菜鸟快乐游戏编程_pygame(2)
Python菜鸟快乐游戏编程_pygame(博主录制,2K分辨率,超高清) https://study.163.com/course/courseMain.htm?courseId=100618802 ...
- HTML页面只能使用微信浏览器打开
看到一个项目,刚开始还以为是APP,只能用微信打开.仔细看了下原来是个web项目,只是禁用了其他浏览器打开,只能用微信浏览器打开.加上前端页面用了类似mui的模板,就更像APP了. 百度了下,参考 h ...
- python之路(6)迭代器和生成器
目录 迭代器(Iterator) 生成器(Generator) 迭代器 迭代器协议:对象提供一个next方法,执行该方法要么返回下一项,要么引起一个Stopiteration异常 可迭代对象:实现了 ...
- 定时调度系列之Quartz.Net详解
一. 背景 我们在日常开发中,可能你会遇到这样的需求:"每个月的3号给用户发信息,提醒用户XXX "."每天的0点需要统计前一天的考勤记录"."每个月 ...
- Arduino语法-变量和常量
变量的声明: int led=11 一般变量的声明方法为类型名+变量名+变量初始化值.变量名的写法约定为首字母小写 变量的作用范围又称为作用域,变量的作用范围与该变量在哪儿声明有关,大致分为如下两种: ...
- python捕获异常及方法总结
调试Python程序时,经常会报出一些异常,异常的原因一方面可能是写程序时由于疏忽或者考虑不全造成了错误,这时就需要根据异常Traceback到出错点,进行分析改正:另一方面,有些异常是不可避免的,但 ...
- python3三角函数
三角函数 acos(x) 返回x的反余弦弧度值. asin(x) 返回x的反正弦弧度值. atan(x) 返回x的反正切弧度值. atan2(y, x) 返回给定的 X 及 Y 坐标值的反正切 ...
- spring boot集成websocket实现聊天功能和监控功能
本文参考了这位兄台的文章: https://blog.csdn.net/ffj0721/article/details/82630134 项目源码url: https://github.com/zhz ...
- ABP core学习之一 使用Mysql数据库
修改项目EntityFrameworkCore的相关内容 1.添加类库 使用nuget包管理器,添加Pomelo.EntityFrameworkCore.MySql 2.TradeErpDbConte ...