2017 CCPC秦皇岛 H.Prime Set(二分图匹配+分类讨论)
Posted kaka0010
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2017 CCPC秦皇岛 H.Prime Set(二分图匹配+分类讨论)相关的知识,希望对你有一定的参考价值。
原题链接:https://ac.nowcoder.com/acm/problem/14372
题意
简化一下题意,就是你可以从n个数中选择k对数,要求选择的ai,aj满足
a
i
+
a
j
=
p
r
i
m
e
a_i+a_j=prime
ai+aj=prime且
i
!
=
j
i!=j
i!=j
接着将选择的k对取∪,问最大的集合size是多少。
分析
先考虑怎么合成质数,一般情况下质数都是奇数,因此肯定是奇数+偶数合成,当然存在2的例外。先不考虑2,那么就变成二分图的形式,我们先求最大匹配。假设最大匹配为ans,如果ans>=k,那么答案直接输出 k ∗ 2 k*2 k∗2。接下来考虑未匹配的1,如果存在,我们尽量先进行(1,1)匹配,然后再考虑可匹配点个数,假设剩余可匹配点的个数为num,那么答案就是 a n s ∗ 2 + m i n ( k − a n s , n u m ) ans*2+min(k-ans,num) ans∗2+min(k−ans,num)。
Code
#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define re register
typedef long long ll;
typedef pair<ll, ll> PII;
typedef unsigned long long ull;
const ll inf = 1e18;
const int N = 2e6 + 10, M = 1e6 + 10;
const int mod = 1e9 + 7;
vector<int> g[N];
int match[3010], vis[3010];
bool find(int x) {
for (auto v : g[x]) {
if (!vis[v]) {
vis[v] = 1;
if (!match[v] || find(match[v])) {
match[v] = x;
return true;
}
}
}
return false;
}
int a[N], b[N], c[N];
int prime[N];
bool is_prime[N];
void get_prime(){
int k = 0;
memset(is_prime, true, sizeof is_prime);
is_prime[0] = is_prime[1] = false;
for(int i = 2 ; i < N;i++){
if (is_prime[i]) prime[++k] = i;
for(int j = 1; j <= k && i * prime[j] < N;j++){
is_prime[i * prime[j]] = false;
if(i % prime[j] == 0) break;
}
}
}
void solve() {
get_prime();
int T; cin >> T; while (T--) {
int n, k; cin >> n >> k;
for (int i = 1; i <= n; i++) g[i].clear(), match[i] = 0, b[i] = c[i] = 0;
for (int i = 1; i <= n; i++) cin >> a[i];
vector<int> odd, even;
for (int i = 1; i <= n; i++) {
if (a[i] % 2 == 0) even.push_back(i);
if (a[i] % 2 == 1) odd.push_back(i);
}
int f = 0;
for (auto u : even) {
for (auto v : odd) {
if (is_prime[a[u]+a[v]]) {
g[u].push_back(v);
if (a[v] == 1) f = 1;
c[u] = c[v] = 1;
}
}
}
int ans = 0;
for (int i = 1; i <= n; i++) {
if (a[i] % 2 == 1) continue;
memset(vis, 0, sizeof vis);
if (find(i)) ans++, b[i] = 1;
}
if (ans >= k) printf("%d\\n", k*2);
else {
int cnt = 0, num = 0;
for (auto u : even) if (!b[u] && c[u]) num++;
for (auto v : odd) {
if (match[v]) b[v] = 1;
if (!b[v] && c[v]) num++;
if (!match[v] && a[v] == 1) cnt++;
}
if (!f) {
if (cnt > 1) num += cnt % 2;
cnt /= 2;
if ((cnt + ans) * 2 >= n) printf("%d\\n", n);
else if (cnt + ans >= k) printf("%d\\n", k*2);
else {
int mx = k - ans - cnt;
printf("%d\\n", (cnt+ans)*2+min(mx, num));
}
} else {
cnt /= 2;
num -= cnt * 2;
if ((cnt + ans) * 2 >= n) printf("%d\\n", n);
else if (cnt + ans >= k) printf("%d\\n", k*2);
else {
int mx = k - ans - cnt;
printf("%d\\n", (cnt+ans)*2+min(mx, num));
}
}
}
}
}
signed main() {
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
#ifdef ACM_LOCAL
freopen("input", "r", stdin);
freopen("output", "w", stdout);
#endif
solve();
return 0;
}
以上是关于2017 CCPC秦皇岛 H.Prime Set(二分图匹配+分类讨论)的主要内容,如果未能解决你的问题,请参考以下文章
[CCPC] 2017秦皇岛H Prime Set | 二分图最大匹配 [据说是个金牌题]
ZOJ-3988 2017CCPC-秦皇岛 Prime Set 二分图最大匹配 匈牙利
[CCPC] 2017秦皇岛 NumbersI | Java BigInteger | 贪心