RT,用的是并查集加二进制拆分的多重背包,为什么错了呢?
// P2170 选学霸
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#define MN 200005
using namespace std;
inline int read() {
int x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-') f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9')
x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
return x * f;
}
struct thing {
int v, m;
} things[MN];
int n, m, k;
int fa[MN], g[MN], vis[MN];
int cnt, s[MN], dp[MN], tot;
int find(int x) {
while (x != fa[x]) x = fa[x] = fa[fa[x]];
return fa[x];
}
int main() {
int a, b;
freopen("/mnt/d/workspace/Exercise/data/P2170_2.in", "r", stdin);
n = read(), m = read(), k = read();
for (int i = 1; i <= n; i++) fa[i] = i, g[i] = 1;
for (int i = 0; i < k; i++) {
a = find(read()), b = find(read());
fa[a] = b, g[b] += g[a];
}
for (int i = 1; i <= n; i++)
if (!vis[find(i)]) vis[find(i)] = 1, s[cnt++] = g[find(i)];
sort(s, s + cnt), a = s[0], b = 1;
for (int i = 1; i <= cnt; i++)
if (a != s[i])
things[tot++] = thing{a, b}, a = s[i], b = 0;
else
b++;
dp[0] = 1;
for (int i = 0; i < tot; i++) {
int now = 1, temp = things[i].m, a = things[i].v;
while (1)
if (temp > now) {
temp -= now;
for (int j = m * 2; j >= now * a; j--)
if (dp[j - now * a]) dp[j] = 1;
now *= 2;
} else {
for (int j = m * 2; j >= temp * a; j--)
if (dp[j - temp * a]) dp[j] = 1;
break;
}
}
for (int i = m, j = m; i >= 0; i--, j++)
if (dp[i]) {
printf("%d", i);
return 0;
} else if (dp[j]) {
printf("%d", j);
return 0;
}
return 0;
}