比赛链接:
https://codeforces.com/contest/1715
D. 2+ doors
题意:
长为 \(n\) 的序列,已知 \(q\) 条关系,\(i, j, x\) 表示 \(a_i | a_j = x\),问满足条件的字典序最小的序列是什么。
思路:
如果 \(x\) 某位上为 0,说明这两个位置的数的这一位都是 0。
如果某位为 1,为了让字典序小,肯定要让 0 往前靠。
建立一个图,\(i\) 和 \(j\) 相连边权为 \(x\),如果当前这位为 1,且之前有一位已经是 0 了,那么这一位只能是 1 了,不然就可以是 0。
再考虑一个特殊情况,\(i\) 和 \(j\) 相等的时候,这个位置只能是 \(x\) 了,不会发生改变。
代码:
#include <bits/stdc++.h>
using namespace std;
#define LL long long
int main(){
ios::sync_with_stdio(false);cin.tie(0);
int n, q;
cin >> n >> q;
vector <int> ans(n + 1, (1 << 30) - 1);
vector < vector < pair<int, int> > > e(n + 1);
for (int i = 1; i <= q; i ++ ){
int u, v, w;
cin >> u >> v >> w;
ans[u] &= w;
ans[v] &= w;
e[u].push_back({v, w});
e[v].push_back({u, w});
}
for (int u = 1; u <= n; u ++ ){
for (int j = 0; j < 30; j ++ ){
if (ans[u] >> j & 1){
bool ok = false;
for (auto [v, w] : e[u]){
if (v == u || !(ans[v] >> j & 1)){
ok = true;
}
}
if (!ok) ans[u] ^= (1 << j);
}
}
cout << ans[u] << " \n"[u == n];
}
return 0;
}