[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;
}

浙公网安备 33010602011771号