首页 > 其他 > 详细

ARC121F - Logical Operations on Tree

时间:2021-05-30 22:50:07      阅读:18      评论:0      收藏:0      [点我收藏+]

ARC121F - Logical Operations on Tree

题目大意

给定一棵树,现在对于每一个点加上权值\(a_i\in\{0,1\}\),每一条边加上操作\(opt_i\in\{\vee,\wedge\}\)

每次操作选择一条边收缩两边的点,权值为两者操作的结果

对于所有\(2^{2n-1}\)种方案,求出所有 存在一种收缩顺序使得最终剩余的点权值为1的 方案数


分析

一开始我以为先做\(\vee\),然后做\(\wedge\),然后发现\(1 - \vee - 0 - \wedge -0\)就卡掉了

仔细分析实际上是:

如果一个0旁边有一个\(\wedge\),那么这个0通过操作一定会把另一边的值赋为\(0\)

为了浪费尽量少的1,这样的操作应该先做


因此,贪心的策略是:

1.先一直收缩到所有\(\wedge\)旁边都是1

2.然后任意顺序做

所以实际上最优决策是先做\(\wedge\)再做\(\vee\)

那么一个方案合法的判定:

存在一个\(\wedge\)边连成的联通块,其中所有数都是1

const int N=1e5+10,P=998244353;

int n;
vector <int> G[N];
int dp[N][2];
void dfs(int u,int f){
	dp[u][0]=dp[u][1]=1;
	for(int v:G[u]) if(v!=f) {
		dfs(v,u);
		int t[2]={0,0};
		rep(i,0,1) rep(j,0,1) t[i&j]=(t[i&j]+1ll*dp[u][i]*dp[v][j])%P;
		rep(i,0,1) t[i]=(t[i]+1ll*dp[u][i]*dp[v][0])%P;
		dp[u][0]=t[0],dp[u][1]=t[1];
	}
}

int main(){
	n=rd();
	rep(i,2,n) {
		int u=rd(),v=rd();
		G[u].pb(v),G[v].pb(u);
	}
	dfs(1,0);
	int ans=1;
	rep(i,1,2*n-1) ans=ans*2%P;
	printf("%d\n",(ans-dp[1][0]+P)%P);
}

ARC121F - Logical Operations on Tree

原文:https://www.cnblogs.com/chasedeath/p/14829004.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!