CF543D Road Improvement 题解

Codeforces
Luogu

Description.

\(n\) 个点的树,给边染色。
一个合法的方案定义为所有点到 \(x\) 的路径上只有一条黑边。
对所有 \(x\) 求出合法方案方案数。

Solution.

哈哈,这题我出思路用了 1min,然后被代码细节折磨了 4+h!!!!出题人死个马

首先定义 \(f_{x,0}\)\(f_{x,1}\)\(x\) 节点祖先 没有/有 黑边的方案数。
然后有一个显然的转移,就是

\[f_{x,0}=\prod_{y\in\text{son}(x)}(f_{y,0}+f_{y,1})\\ f_{x,1}=\prod_{y\in\text{son}(x)}f_{y,1}\\ \]

挺显然的,就是枚举这条边是否染黑。

确认完正确性后,就直接开始考虑换根。
定义 \(g_{x,0},g_{x,1}\) 表示以 \(x\) 为根总共的答案。
根据换根的套路,写出了这样一份代码
感觉根本没问题,但是 WA on test 10。
就你考虑定义 \(f0,f1\) 分别如果把它父亲当作子树的贡献,那有
\(f0=\frac{g_{fa,0}}{f_{x,0}+f_{x,1}},f1=\frac{g_{fa,1}}{f_{x,1}}\)
就考虑把当前孩子的贡献去掉。
然后就调啊调啊调啊调啊,最后发现。
tm 这个 \(f_{x,0}+f_{x,1} \bmod P\) 是可以等于 \(0\)
然后 tm 就没逆元了,卡这个出题人怕不是马早没了。

然后直接拆一下式子,记录乘上的 \(0\) 的个数。
然后直接做就做完了,但是细节挺多的

Coding.

点击查看代码
//Coded by Kamiyama_Shiki on 2021.11.16 {{{
//是啊……你就是那只鬼了……所以被你碰到以后,就轮到我变成鬼了
#include<bits/stdc++.h>
#define debug(...) fprintf(stderr,__VA_ARGS__)
using namespace std;typedef long long ll;
template<typename T>inline void read(T &x)
{
	x=0;char c=getchar(),f=0;
	for(;c<48||c>57;c=getchar()) if(!(c^45)) f=1;
	for(;c>=48&&c<=57;c=getchar()) x=(x<<1)+(x<<3)+(c^48);
	f?x=-x:x;
}
template<typename T,typename...L>inline void read(T &x,L&...l) {read(x),read(l...);}//}}}
const int N=200005,P=1000000007;
int fc[N],fi[N],iv[N];//dbinit{{{
inline int ksm(int x,int q=P-2) {int r=1;for(;q;q>>=1,x=1ll*x*x%P) if(q&1) r=1ll*r*x%P;return r;}
inline void dbinit(int n=N-1)
{
	fc[0]=1;for(int i=1;i<=n;i++) fc[i]=1ll*fc[i-1]*i%P;
	iv[1]=1;for(int i=2;i<=n;i++) iv[i]=1ll*iv[P%i]*(P-P/i)%P;
	fi[0]=1;for(int i=1;i<=n;i++) fi[i]=1ll*fi[i-1]*iv[i]%P;
}
inline int C(int n,int m) {return n<0||m<0||n<m?0:1ll*fc[n]*fi[m]%P*fi[n-m]%P;}//}}}
struct edge{int to,nxt;}e[N<<1];int n,et,head[N],f[N][2],g[N][2],h[N];
inline void adde(int x,int y) {e[++et]=(edge){y,head[x]},head[x]=et;}
inline void dfs0(int x,int fa)
{
	f[x][0]=f[x][1]=1;
	for(int i=head[x],y;i;i=e[i].nxt) if((y=e[i].to)!=fa)
		dfs0(y,x),f[x][0]=1ll*f[x][0]*(f[y][0]+f[y][1])%P,f[x][1]=1ll*f[x][1]*f[y][1]%P;
}
inline void dfs1(int x,int fa)
{
	//h[y]=f[x][0]/(f[y][0]+f[y][1])*(h[x]+f1)
	int f1=1ll*g[fa][1]*ksm(f[x][1])%P,tmp=1,tot=0;
	g[x][0]=1ll*f[x][0]*(h[x]+f1)%P,g[x][1]=1ll*f[x][1]*f1%P;//h[x]=f0
	for(int i=head[x],y;i;i=e[i].nxt) if((y=e[i].to)!=fa)
		{if((f[y][0]+f[y][1])%P) tmp=1ll*tmp*(f[y][0]+f[y][1])%P;else tot++;}
	for(int i=head[x],y;i;i=e[i].nxt) if((y=e[i].to)!=fa)
		{if((f[y][0]+f[y][1])%P) h[y]=tot?0ll:1ll*tmp*ksm(f[y][0]+f[y][1])%P;else h[y]=tot-1?0:tmp;}
	for(int i=head[x],y;i;i=e[i].nxt) if((y=e[i].to)!=fa) h[y]=1ll*h[y]*(f1+h[x])%P;
	for(int i=head[x];i;i=e[i].nxt) if(e[i].to!=fa) dfs1(e[i].to,x);
}
int main()
{
	read(n);for(int i=2,f;i<=n;i++) read(f),adde(f,i),adde(i,f);
	dfs0(1,0),h[1]=0,g[0][1]=f[1][1],dfs1(1,0);
	for(int i=1;i<=n;i++) printf("%d%c",g[i][0],i==n?'\n':' ');
	return 0;
}
posted @ 2021-11-16 16:38  Peal_Frog  阅读(48)  评论(0编辑  收藏  举报