[ABC396E] Min of Restricted Sum

[ABC396E] Min of Restricted Sum

题意

构造一个和最小的长度为 \(n\) 的非负整数序列 \(a\),使得该序列满足 \(m\) 个条件 \(x_i,y_i,z_i\),表示 \(a_{x_i}\text{xor }a_{y_i}=z_i\)

思路

首先我们将 \(x_i,y_i,z_i\) 的限制转化为一个无向图,在图上考虑问题。

发现当 \(a_{x_i}\) 确定时,\(a_{y_i}\) 也一定确定,则对于图中的一个连通块,只需要确定其中的一个值,其它的值也会一起被确定。

对于一个连通块中合法的一种方案 \(a_{id_1},a_{id_2},\cdots,a_{id_{len}}\),将所有数异或一个值 \(x\) 仍然满足限制条件,因为相同的数字异或值为 \(0\)

于是可以对每个连通块将其中的一个初值设为 \(0\) 进行 dfs 算出剩余的 \(a_i\),顺便判一下无解,再通过将所有数异或一个值 \(x\) 使得 \(a_i\) 之和最小。

对于所有 \(a_i\) 在二进制下的第 \(k\) 位若的 \(1\) 的数量大于 \(0\) 的数量,则可以通过异或 \(2^{k-1}\) 反转 \(0\)\(1\),也就使得整体的和减小,对每一位计算即可求出 \(x\)

代码

#include <bits/stdc++.h>
using namespace std;
struct node{
	int x,d;
};
int n,m,a[200005],ans[200005];
bool has=true;
vector<node> t[200005];
vector<int> to;
void dfs(int x){
	to.push_back(x);
	for(node v:t[x]){
		if(ans[v.x]!=-1){
			if((ans[x]^v.d)!=ans[v.x]){
				has=false;
				return;
			}
		}
		else{
			ans[v.x]=ans[x]^v.d;
			dfs(v.x);
			if(!has) return;
		}
	}
}
signed main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr),cout.tie(nullptr);
	cin>>n>>m;
	for(int i=1;i<=n;i++)
		ans[i]=-1;
	for(int x,y,d,i=1;i<=m;i++){
		cin>>x>>y>>d;
		t[x].push_back({y,d});
		t[y].push_back({x,d});
	}
	for(int i=1;i<=n;i++){
		if(ans[i]==-1){
			ans[i]=0,to.clear();
			dfs(i);
			int xr=0;
			for(int j=0;j<32;j++){
				int cc=0;
				for(int v:to)
					if(ans[v]&(1<<j)) cc++;
				if(cc>(int)to.size()/2)
					xr|=(1<<j);
			}
			for(int v:to)
				ans[v]^=xr;
		}
	}
	if(!has)
		cout<<-1;
	else
		for(int i=1;i<=n;i++)
			cout<<ans[i]<<" ";
	return 0;
}
posted @ 2025-03-26 11:03  WuMin4  阅读(12)  评论(0)    收藏  举报