题目描述
要求构造一个长度为 的数组 ,首先满足以下 个条件。其中每个条件包含三个数 ,表示在数组中 。在满足以上条件的前提下,输出字典序最小的数组,题目保证这样的答案存在。
输入样例
4 3
1 2 3
1 3 2
4 1 2
输出样例
0 3 2 2
题目分析
这是一道基于 按位贪心 的构造问题。
首先我们对于最终数组的每一位进行分析,即在 的第 位中,若两者的或值为 ,则意味着 和 的第 位必为 ,我们先按照这个条件对相应的每一个数增加限制;若或值为 ,则意味着两数的第 位至少有一个 ,我们按照贪心的思想,要保证数组的字典序最小,则应该优先给 的第 位与 。因此我们统计完所有的 次询问对 的第 位的所有 的约束,按所有与 相关的 的第 位是否在第一个条件下强制为 来进行最后的判断。
注意一定要按位进行分析,而不能直接按询问的先后进行分析,通过构造样例 ,得到答案 而最优解为 可知这样得到的答案并非最优。
Accept代码
#include <bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int n, q;
cin >> n >> q;
vector<int> x(q), y(q), f(q), res(n + 1);
for (int i = 0; i < q; i ++)
{
cin >> x[i] >> y[i] >> f[i];
if (x[i] > y[i]) swap(x[i], y[i]);
}
for (int i = 0; i < 30; i ++)
{
vector<vector<int>> g(n + 1);
vector<int> h(n + 1);
for (int j = 0; j < q; j ++)
{
if ((f[j] >> i) % 2 == 0) h[x[j]] = h[y[j]] = 1;
else g[x[j]].push_back(y[j]);
}
for (int j = 1; j <= n; j ++)
{
if ((res[j] >> i) % 2 || g[j].empty()) continue;
bool flg = true;
for (int k : g[j])
if (k == j || h[k])
{
res[j] |= 1 << i;
flg = false;
break;
}
if (flg) for (int k : g[j])
res[k] |= 1 << i;
}
}
for (int i = 1; i <= n; i ++) cout << res[i] << ' ';
return 0;
}