SCOI2019 RGB [容斥]

传送门
考虑只有一个绿点的情况,就是一个裸的树形 dp,强制选当前点
f u , r = ∏ ( f v , r + 1 ) , f u , b = ∏ ( f v , b + 1 ) f_{u,r} =\prod (f_{v,r}+1),f_{u,b} =\prod (f_{v,b}+1) fu,r=(fv,r+1),fu,b=(fv,b+1)
a n s = f u , r ∗ f u , b ans=f_{u,r}*f_{u,b} ans=fu,rfu,b
我们可以枚举所有绿点算一遍答案,考虑有哪些情况会算重
如果绿点不相连,很明显不会重,会重的情况只有绿色点聚成一坨的时候
我们要让一坨的点的贡献只算一次,发现点数-边数=1
于是可以枚举每个绿点,在减去每条边的贡献就可以让一个连通块只算一次了

#include<bits/stdc++.h>
#define N 4050
using namespace std;
const int Mod = 1000000007;
int read(){
	int cnt = 0, f = 1; char ch = 0;
	while(!isdigit(ch)){ ch = getchar(); if(ch == '-') f = -1;}
	while(isdigit(ch)){ cnt = cnt * 10 + (ch-'0'), ch = getchar();}
	return cnt * f;
}
typedef long long ll;
ll add(ll a, ll b){ return (a + b) % Mod;}
ll mul(ll a, ll b){ return (a * b) % Mod;}
int first[N], nxt[N], to[N], w[N], tot;
void add(int x, int y, int z){
	nxt[++tot] = first[x], first[x] = tot, to[tot] = y, w[tot] = z;
}
int n, W, col[N];
struct Edge{ int u, v, w;} E[N];
ll ans, fR[N], fB[N];
void dfs(int u, int fa, int dis){
	if(dis > W){ fR[u] = fB[u] = 0; return;}
	if(col[u] != 1) fB[u] = 1;
	if(col[u] != 3) fR[u] = 1;
	for(int i = first[u]; i; i = nxt[i]){
		int t = to[i]; if(t == fa) continue;
		dfs(t, u, dis + w[i]);
		fB[u] = mul(fB[u], fB[t] + 1);
		fR[u] = mul(fR[u], fR[t] + 1);
	}
}
void Yolanda(int u){ dfs(u, 0, 0); ans = add(ans, mul(fR[u], fB[u]));}
void FSY(int u, int v, int w){
	dfs(u, v, w); dfs(v, u, w);
	ans = add(ans, Mod - mul(mul(fR[u], fB[u]), mul(fR[v], fB[v])));
}
int main(){
	n = read(), W = read(); string s; cin >> s;
	for(int i = 0; i < n; i++){
		if(s[i] == 'R') col[i+1] = 1;
		if(s[i] == 'G') col[i+1] = 2;
		if(s[i] == 'B') col[i+1] = 3; 
	}
	for(int i = 1; i < n; i++){
		int x = read(), y = read(), z = read();
		add(x, y, z); add(y, x, z);
		E[i] = (Edge){ x, y, z };
	} 
	for(int i = 1; i <= n; i++) if(col[i] == 2) Yolanda(i);
	for(int i = 1; i < n; i++) if(col[E[i].u] == 2 && col[E[i].v] == 2) FSY(E[i].u, E[i].v, E[i].w);
	cout << ans; return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
中描述了一个幼儿园里分配糖果的问题,每个小朋友都有自己的要求。问题的输入包括两个整数NN和KK,表示幼儿园里的小朋友数量和要满足的要求数量。接下来的KK行表示小朋友们的要求,每行有三个数字,XX,AA,BB。如果X=1,表示第AA个小朋友分到的糖果必须和第BB个小朋友分到的糖果一样多;如果X=2,表示第AA个小朋友分到的糖果必须少于第BB个小朋友分到的糖果;如果X=3,表示第AA个小朋友分到的糖果必须不少于第BB个小朋友分到的糖果;如果X=4,表示第AA个小朋友分到的糖果必须多于第BB个小朋友分到的糖果;如果X=5,表示第AA个小朋友分到的糖果必须不多于第BB个小朋友分到的糖果。这个问题可以被看作是一个差分约束系统的问题。 具体地说,可以使用差分约束系统来解决这个问题。差分约束系统是一种通过给变量之间的关系添加约束来求解最优解的方法。对于这个问题,我们需要根据小朋友们的要求建立约束条件,并通过解决这个约束系统来得出最小的糖果数量。 在问题的输入中,X的取值范围为1到5,分别对应不同的关系约束。根据这些约束,我们可以构建一个差分约束图。图中的节点表示小朋友,边表示糖果数量的关系。根据不同的X值,我们可以添加相应的边和权重。然后,我们可以使用SPFA算法(Shortest Path Faster Algorithm)来求解这个差分约束系统,找到满足所有约束的最小糖果数量。 需要注意的是,在读取输入时需要判断X和Y是否合法,即是否满足X≠Y。如果X=Y,则直接输出-1,因为这种情况下无法满足约束条件。 综上所述,为了满足每个小朋友的要求,并且满足所有的约束条件,我们可以使用差分约束系统和SPFA算法来求解这个问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [【差分约束系统】【SCOI2011】糖果 candy](https://blog.csdn.net/jiangzh7/article/details/8872699)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [P3275 [SCOI2011]糖果(差分约束板子)](https://blog.csdn.net/qq_40619297/article/details/88678605)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FSYo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值