题解:P3429 [POI 2005] DWA-Two Parties
第一次独立做出来紫诶。
看到这种题下意识想到高斯消元。
令 \(x_i\) 表示第 \(i\) 个人的选择,\(x_i\) 只能是 \(0\) 或 \(1\) 之一,即前往哪个派对。对于每个人,ta 会对答案产生贡献当且仅当其同派对邻居数量为偶数。因此,我们可以将问题转换为 \(\mathrm{GF(2)}\) 上的问题。
对于一个关系 \((i,j)\),当且仅当 \(x_i=x_j\) 时 \(j\) 才会影响 \(i\)。同时一个 \(j\) 影响 \(i\),也必需让 \((i,j)\) 这个关系存在。所以只有以上两个条件都满足的时候,\(j\) 才会影响 \(i\)。故我们可以再设 \(a_{i,j}\) 表示 \(i\) 和 \(j\) 是否存在关系。由于两者要同时满足,所以一个人 \(j\) 在 \(a_{i,j}[x_j = x_i] = 1\) 时才影响 \(i\),而易发现 \([x_j = x_i]=1\oplus x_i\oplus x_j\)。根据题目要求,影响第 \(i\) 个人的人数为偶数时 \(i\) 才会对答案产生贡献,即:
时 \(i\) 会计入答案。
令 \(d_i\) 表示与 \(i\) 有关系的人数个数,\(c_i = d_i\bmod2\),展开上面的式子:
移项后可得
于是对于每个 \(i\),我们都得到了这样一个方程,组合到一起就变成了在 \(\mathrm{GF(2)}\) 上的线性方程。
最终我们希望选择一组 \(x_i\),使得尽可能多的方程成立,并且
定理(Gallai 环-余环划分定理):对于任意无向图,总存在一种将顶点划分为两个集合的方案,使得每个顶点在自己所属集合内部的邻居数量为偶数。
根据该定理,存在一种划分使所有顶点在自己所属集合中的邻居数均为偶数。将这两个集合分别记为 \(x_i=0\) 和 \(x_i=1\),即可得到上述方程组的一组解。因此方程组一定有解,可以直接进行高斯消元。
最终根据求解出的 \(x_i\) 分配方案输出即可,由于题目要求任意合法方案都没问题,所以我们令最终的自由元为 \(0\) 即可。
AC 代码见下。
#include<bits/stdc++.h>
#define TESTING 0
#define ift if (TESTING)
#define ft first
#define sd second
#define pb push_back
#define rep(i, a, b) for (int i = (a); i <= (b); i++)
#define per(i, a, b) for (int i = (a); i >= (b); i--)
#define int long long
#define qwq while (1) cout << "qwq" << "\n"
#define debug(x) cout << #x << "=" << x << "\n"
#define pii pair<int, int>
using namespace std;
const int N = 200 + 5, INF = 0x3f3f3f3f;
int n, x[N];
bitset<N> a[N];
void Gauss() {
int row = 1;
for (int col = 1; col <= n; col++) {
int p = row;
while (p <= n && !a[p][col]) p++;
if (p > n) continue;
swap(a[p], a[row]);
for (int i = 1; i <= n; i++) {
if (i != row && a[i][col])
a[i] ^= a[row];
}
row++;
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
if (a[i][j]) {
x[j] = a[i][n + 1];
break;
}
}
}
}
auto init() -> void{}
auto solution() -> void{
cin >> n;
rep(i, 1, n) {
int d;
cin >> d;
a[i][n + 1] = d & 1;
if (d & 1) a[i][i] = 1;
rep(j, 1, d) {
int v;
cin >> v;
a[i][v] = 1;
}
}
Gauss();
vector<int> ans;
rep(i, 1, n) {
if (x[i]) ans.pb(i);
}
cout << ans.size() << '\n';
for (auto v : ans) cout << v << ' ';
cout << '\n';
}
auto main() -> signed{
ios :: sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int T = 1;
// cin >> T;
while (T--){
init();
solution();
}
return 0;
}

浙公网安备 33010602011771号