tree

对于 \(n\) 个点带标号的无根森林,计算所有森林的树的个数的 \(k\) 次方,对 \(998244353\) 取模。


自闭,错了一堆关于长度的问题,这里以后一定要注意

比如需要 \(n\) 次多项式的点值,但是却使用了乘法后的 \(2\times n\) 多项式的前 \(n\) 项点值;对 \(2\times n\) 多项式按长度 \(2\times n\) DFT 直接什么的

以及还是容易写错 exp 板子的问题...


由 \(prufer\) 序列,我们知道树的生成函数是 \(A(x)=\sum_{i\ge 0}\frac{i^{i-2}}{i!}x^i\) ,注意这里我们要算的话需要定义 \(0\) 个点的树个数是 \(0\)

设森林个数的 \(k\) 次方的生成函数是 \(B_k(x)\) ,我们有

\[B_k(x)=\sum_{i\ge 0}i^k\frac{A^i(x)}{i!}
\]

我们可以知道 \(B_0=e^A\)

因为 \(k\) 比较小,并且我们知道 \(B_0\) ,所以考虑建立 \(B_k\) 与 \(B_{k-1}\) 之间的递推关系式

因为关键在于 \(i^k\) 与 \(i^{k-1}\) 不一样,所以考虑求导去凑

\[\begin{aligned}
B_{k-1}'(x)&=\sum_{i\ge 0}\frac{i^{k-1}}{i!}(A^i(x))'\\
&=\sum_{i\ge 0}\frac{i^k}{i!}A^{i-1}(x)A'(x)\\
&=\frac{A'(x)}{A(x)}\sum_{i\ge 0}\frac{i^k}{i!}A^i(x)\\
&=\frac{A'(x)}{A(x)}B_k(x)
\end{aligned}
\]

因此

\[B_k(x)=\frac{A(x)B'_{k-1}(x)}{A'(x)}
\]

然后套上多项式板子即可

复杂度 \(O(kn\log n)\)


Code:

#include <cstdio>
#include <cctype>
#include <algorithm>
using std::min;
const int SIZE=1<<21;
char ibuf[SIZE],*iS,*iT;
//#define gc() (iS==iT?(iT=(iS=ibuf)+fread(ibuf,1,SIZE,stdin),iS==iT?EOF:*iS++):*iS++)
#define gc() getchar()
template <class T>
void read(T &x)
{
int f=0;x=0;char c=gc();
while(!isdigit(c)) f|=c=='-',c=gc();
while(isdigit(c)) x=x*10+c-'0',c=gc();
if(f) x=-x;
}
const int N=(1<<17)+10;
const int mod=998244353,G=3,Gi=332748118;
inline int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
#define mul(x,y) (1ll*(x)*(y)%mod)
int qp(int d,int k){int f=1;while(k){if(k&1)f=mul(f,d);d=mul(d,d),k>>=1;}return f;}
int turn[N],fac[N],inv[N];
void NTT(int *a,int lim,int typ)
{
int L=-1;for(int i=1;i<lim;i<<=1) ++L;
for(int i=0;i<lim;i++)
{
turn[i]=turn[i>>1]>>1|(i&1)<<L;
if(i<turn[i]) std::swap(a[i],a[turn[i]]);
}
for(int le=1;le<lim;le<<=1)
{
int wn=qp(typ?G:Gi,(mod-1)/(le<<1));
for(int i=0;i<lim;i+=le<<1)
{
int w=1;
for(int j=i;j<i+le;j++,w=mul(w,wn))
{
int x=a[j],y=mul(w,a[j+le]);
a[j]=add(x,y),a[j+le]=add(x,mod-y);
}
}
}
if(!typ)
{
int inv=qp(lim,mod-2);
for(int i=0;i<lim;i++) a[i]=mul(a[i],inv);
}
}
int iva[N],ivb[N];
void polyinv(int *a,int *b,int lim)
{
if(lim==1){b[0]=qp(a[0],mod-2);return;}
polyinv(a,b,lim>>1);
for(int i=0;i<lim<<1;i++) iva[i]=ivb[i]=0;
for(int i=0;i<lim;i++) iva[i]=a[i],ivb[i]=b[i];
NTT(iva,lim<<1,1),NTT(ivb,lim<<1,1);
for(int i=0;i<lim<<1;i++) iva[i]=mul(ivb[i],add(2,mod-mul(iva[i],ivb[i])));
NTT(iva,lim<<1,0);
for(int i=0;i<lim;i++) b[i]=iva[i];
}
void polyqd(int *a,int lim)
{
for(int i=0;i<lim-1;i++) a[i]=mul(a[i+1],i+1);
a[lim-1]=0;
}
void polyint(int *a,int lim)
{
for(int i=lim-1;i;i--)
a[i]=mul(a[i-1],mul(fac[i-1],inv[i]));
a[0]=0;
}
int lna[N],lnb[N];
void polyln(int *a,int lim)
{
for(int i=0;i<lim<<1;i++) lna[i]=lnb[i]=0;
for(int i=0;i<lim;i++) lna[i]=a[i];
polyinv(lna,lnb,lim);
polyqd(lna,lim);
NTT(lna,lim<<1,1),NTT(lnb,lim<<1,1);
for(int i=0;i<lim<<1;i++) lna[i]=mul(lna[i],lnb[i]);
NTT(lna,lim<<1,0);
polyint(lna,lim);
for(int i=0;i<lim;i++) a[i]=lna[i];
}
int exa[N],exb[N];
void polyexp(int *a,int *b,int lim)
{
if(lim==1){b[0]=1;return;}
polyexp(a,b,lim>>1);
for(int i=0;i<lim<<1;i++) exa[i]=exb[i]=0;
for(int i=0;i<lim;i++) exa[i]=exb[i]=b[i];
polyln(exb,lim);
for(int i=0;i<lim;i++) exb[i]=add(a[i]+(i==0),mod-exb[i]);
NTT(exa,lim<<1,1),NTT(exb,lim<<1,1);
for(int i=0;i<lim<<1;i++) exa[i]=mul(exa[i],exb[i]);
NTT(exa,lim<<1,0);
for(int i=0;i<lim;i++) b[i]=exa[i];
}
int A[N],B[21][N],C[N],D[N];
int main()
{
int n,k;
read(n),read(k);
int lim=1;
while(lim<=n) lim<<=1;
fac[0]=1;for(int i=1;i<=lim<<1;i++) fac[i]=mul(fac[i-1],i);
inv[lim<<1]=qp(fac[lim<<1],mod-2);
for(int i=(lim<<1)-1;~i;i--) inv[i]=mul(inv[i+1],i+1);
A[0]=C[0]=0;A[1]=C[1]=1;
for(int i=2;i<lim;i++) A[i]=C[i]=mul(qp(i,i-2),inv[i]); polyexp(A,B[0],lim);
polyqd(C,lim);
polyinv(C,D,lim); NTT(A,lim<<1,1),NTT(D,lim<<1,1);
for(int i=0;i<lim<<1;i++) A[i]=mul(A[i],D[i]); NTT(A,lim<<1,0);//warning
for(int i=lim;i<lim<<1;i++) A[i]=0;
NTT(A,lim<<1,1); for(int i=1;i<=k;i++)
{
polyqd(B[i-1],lim);
for(int j=lim;j<lim<<1;j++) B[i-1][j]=0;//warning
NTT(B[i-1],lim<<1,1);
for(int j=0;j<lim<<1;j++) B[i][j]=mul(B[i-1][j],A[j]);
NTT(B[i],lim<<1,0);
}
printf("%lld\n",mul(B[k][n],fac[n]));
return 0;
}

2019.6.24

tree 解题报告的更多相关文章

  1. 【LeetCode】863. All Nodes Distance K in Binary Tree 解题报告(Python)

    [LeetCode]863. All Nodes Distance K in Binary Tree 解题报告(Python) 作者: 负雪明烛 id: fuxuemingzhu 个人博客: http ...

  2. 【LeetCode】297. Serialize and Deserialize Binary Tree 解题报告(Python)

    [LeetCode]297. Serialize and Deserialize Binary Tree 解题报告(Python) 标签: LeetCode 题目地址:https://leetcode ...

  3. 【LeetCode】331. Verify Preorder Serialization of a Binary Tree 解题报告(Python)

    [LeetCode]331. Verify Preorder Serialization of a Binary Tree 解题报告(Python) 标签: LeetCode 题目地址:https:/ ...

  4. 【LeetCode】109. Convert Sorted List to Binary Search Tree 解题报告(Python)

    [LeetCode]109. Convert Sorted List to Binary Search Tree 解题报告(Python) 标签(空格分隔): LeetCode 作者: 负雪明烛 id ...

  5. 【LeetCode】236. Lowest Common Ancestor of a Binary Tree 解题报告(Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 日期 题目地址:https://leetcode.c ...

  6. 【LeetCode】99. Recover Binary Search Tree 解题报告(Python)

    [LeetCode]99. Recover Binary Search Tree 解题报告(Python) 标签(空格分隔): LeetCode 题目地址:https://leetcode.com/p ...

  7. 【LeetCode】662. Maximum Width of Binary Tree 解题报告(Python)

    [LeetCode]662. Maximum Width of Binary Tree 解题报告(Python) 标签(空格分隔): LeetCode 题目地址:https://leetcode.co ...

  8. 【LeetCode】623. Add One Row to Tree 解题报告(Python)

    [LeetCode]623. Add One Row to Tree 解题报告(Python) 标签(空格分隔): LeetCode 题目地址:https://leetcode.com/problem ...

  9. POJ 2054 Color a Tree解题报告

    题干 Bob is very interested in the data structure of a tree. A tree is a directed graph in which a spe ...

  10. 【LeetCode】1161. Maximum Level Sum of a Binary Tree 解题报告 (C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 BFS 日期 题目地址:https://leetcod ...

随机推荐

  1. 洛谷T89644 palindrome回文串

    洛谷 T89643 回文串(并查集) 洛谷:https://www.luogu.org/problem/T89643 题目描述 由于 Kiana 实在是太忙了,所以今天的题里面没有 Kiana. 有一 ...

  2. 转 python 字符串前加r

    在打开文件的时候open(r'c:\....') 加r和不加''r是有区别的 'r'是防止字符转义的 如果路径中出现'\t'的话 不加r的话\t就会被转义 而加了'r'之后'\t'就能保留原有的样子 ...

  3. mysql练习题目试水50题,附建库sql代码

    如果你没试过水的话,那一题一题地每一题都敲一遍吧.不管它们对你看来有多么简单.  建库代码 部分题目答案在末尾,可用ctrl f  搜索题号. 作业练习——学生-选课 表结构 学生表: Student ...

  4. [BZOJ2138]stone(Hall定理,线段树)

    Description 话说Nan在海边等人,预计还要等上M分钟.为了打发时间,他玩起了石子.Nan搬来了N堆石子,编号为1到N,每堆 包含Ai颗石子.每1分钟,Nan会在编号在\([L_i,R_i] ...

  5. [Bzoj2243][SDOI2011]染色(线段树&&树剖||LCT)

    题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2243 线段树+树链剖分,在线段树需要每次用lt和rt两个数组记录当前区间的左右边界的颜色 ...

  6. php提交表单时如何保留多个空格及换行的文本样式

    需求是:用户提交表单时屏蔽敏感词的功能.其中敏感词来自服务器端同一路径下的ciku.txt,敏感词通过"|"连接,例如"g|c|a",提交表单时替换敏感词,更重 ...

  7. 4、、多变量线性回归(Linear Regression with Multiple Variables)

    4.1 多维特征 目前为止,我们探讨了单变量/特征的回归模型,现在我们对房价模型增加更多的特征,例如房间数楼层等,构成一个含有多个变量的模型,模型中的特征为(x1,x2,...xn) 增添更多特征后, ...

  8. linux php 中session 多站点共享session问题

    linux php 中session默认file 假如修改为redis php.ini session.save_handler = "files"; session.save_p ...

  9. codeforces hack

    对某一题,首先你自己要先过TEST. 然后回到比赛的PROBLEM列表,把这题后面的锁锁上(锁上了就不能再提交了,所以没把握就别锁了), 然后到ROOM里面,你就可以看别人代码了,下面有HACK按钮, ...

  10. VUE小案例--简易计算器

    这个小案例主要时练习v-model的使用,功能并不完善 <!DOCTYPE html> <html lang="zh-CN"> <head> & ...