F. Leaf Partition 题解
F. Leaf Partition题目来源()
题目大意:给你一颗n个节点的树(根结点为1),要你将叶子节点分成若干个集合,然后设f(x)表示将集合x中所有的叶子结点连成最小的连通图子图,求有多少种划分方法使得所有的f(x)互不相交。
样例:
5
1 1 1 1
输出
12

正解:这里考虑用树形DP。
设 f[x]表示以x为根结点,并且不会再向上走去联通其他点的方案数,g[x]表示以x为根结点,要向上去联通其他点的方案数。
我们可以发现 f[x]=g[x]=Π(v∈son[x])(f[v]+g[v]); 但里面有很多方案数是不可能的 例如 求f[x]时所有的儿子中只有一个向上延伸的。(毕竟有向上延伸的所以必须存在另一个与其联通,所以不能再f[x]这里结束。)
所有f[x]就等于总方案数-不合法的方案数===(设sum=Π(v∈son[x])f[v]),(v∈son[x])f[x]-=sum/f[v]*g[v];
g[x]同理不能存在一个向上延伸都没有的 所以g[x]=g[x]-sum;
注意要取模,所以逆元 long long什么的
答案 就为f[1];
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int i,j,n,m,k,l,e[300001][3],h[300001],tot,x;
long long g[300001],f[300001],mo;
void add(int u,int v)
{
e[++tot][0]=h[u];
e[tot][1]=v;
h[u]=tot;
}
long long ksm(long long x,long long y)
{
long long res=1;
while(y)
{
if(y%2==1) res*=x,res%=mo;
x*=x;x%=mo;y/=2;
}
return res;
}
void dfs(int x)
{
if(h[x]==0){f[x]=g[x]=1;return;}
long long sum=1;f[x]=g[x]=1;
for(int i=h[x];i;i=e[i][0])
{
dfs(e[i][1]);
sum*=f[e[i][1]],sum%=mo;
f[x]*=(g[e[i][1]]+f[e[i][1]]);f[x]%=mo;
g[x]*=(g[e[i][1]]+f[e[i][1]]);g[x]%=mo;
}
for(int i=h[x];i;i=e[i][0])
{
f[x]-=(sum*ksm(f[e[i][1]],mo-2))%mo*g[e[i][1]]%mo;
if(f[x]<0) f[x]+=mo;
}
g[x]-=sum;if(g[x]<0)g[x]+=mo;
}
int main()
{
scanf("%d",&n);mo=998244353;
for(i=2;i<=n;i++)
scanf("%d",&x),add(x,i);
dfs(1);
printf("%lld",f[1]);
}
作者不易,,,ε=(´ο`*)))唉,,,
转载请附上链接Thanks♪(・ω・)ノ

浙公网安备 33010602011771号