时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld
题目描述
Given an array of
n integers
a
1
,a
2
,...,a
n,we say a set
{i,j} is a prime set of the given array, if
i ≠ j and
a
i
+ a
j is prime.
BaoBao has just found an array of
n
integers
a
1
,a
2
,...,a
nin his pocket. He would like to select at most
k
prime set of that array to maximize the size of the union of the selected sets. That is to say, to maximize
by carefully selecting
m
and
p
1
,p
2
,...p
m
, where
m
≤ k and
p
i is a prime set of the given array. Please help BaoBao calculate the maximum size of the union set.
![](https://i-blog.csdnimg.cn/blog_migrate/c6d25e251a0e7a0547bc498381c0fcc0.png)
输入描述:
There are multiple test cases. The first line of the input is an integer T ,indicating the number of test cases. For each test case:The first line contains two integers n and k (1 ≤ n ≤ 3 × 10 3,0 ≤ k ≤), their meanings are described above.
The second line contains n integers a 1,a 2,...,a n, (1 ≤ a i ≤ 10 6) , indicating the given array.t's guaranteed that the sum of n over all test cases will not exceed 10 4.
输出描述:
For each test case output one line containing one integer, indicating the maximum size of the union of at most k prime set of the given array.
示例1
输入
4 4 2 2 3 4 5 5 3 3 4 12 3 6 6 3 1 3 6 8 1 1 1 0 1
输出
4 3 6 0
说明
For the first sample test case, there are 3 prime sets: {1, 2}, {1, 4} and {2, 3}. As k = 2,we can select {1, 4} and {2, 3} to get the largest union set {1, 2, 3, 4} with a size of 4. For the second sample test case, there are only 2 prime sets: {1, 2} and {2, 4}. As k = 3, we can select both of them to get the largest union set {1, 2, 4} with a size of 3. For the third sample test case, there are 7 prime sets: {1, 3}, {1, 5}, {1, 6}, {2, 4}, {3, 5}, {3, 6} and {5, 6}. As k = 3,we can select {1, 3}, {2, 4} and {5, 6} to get the largest union set {1, 2, 3, 4, 5, 6} with a size of 6.
乍一看是个数论题。。其实仔细一看 是个二分匹配。。最小点覆盖。 素数除了2,都是奇数这是显然的。 为了优化图的节点、我们可以把奇数跟偶数分开 左边奇数右边偶数(左右都一样。但是 1的节点要特别注意一下,特殊处理一下,因为1可以跟1组成素数,所以要记录一下1的使用情况最后 sum += num[1](剩余的、未标记的)/2
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <queue>
#include <stack>
#include <vector>
#include <algorithm>
const int MAXN = 6050;
const int MAXM = 5500000;
using namespace std;
struct Node {
int v, next;
}node[MAXM];
int head[MAXN * 2], total;
void init() {
memset(head, -1, sizeof(head));
total = 0;
}
void add(int u, int v) {
node[total] = {v, head[u]};
head[u] = total++;
}
int match[MAXN * 2], vis[MAXN * 2];
bool dfs(int u) {
for (int i = head[u]; i != -1; i = node[i].next) {
int v = node[i].v;
if (!vis[v]) {
vis[v] = 1;
if (match[v] == -1 || dfs(match[v])) {
match[u] = v;
match[v] = u;
return 1;
}
}
}
return 0;
}
int xyl(int n) {
int res = 0;
memset(match, -1, sizeof(match));
for (int i = 0; i < n; ++i) {
memset(vis, false, sizeof(vis));
if (match[i] == -1) {
res += dfs(i);
}
}
return res;
}
int a[10005];
bool prime[2000005];
int shit[20000005];
int prime_num;
void init_prime() {
prime_num = 0;
memset(prime, true, sizeof(prime));
for (int i = 2; i <= 2000000; ++i) {
if (prime[i])
shit[++prime_num] = i;
for (int j = 1; j <= prime_num && shit[j] * i <= 2000000; ++j) {
prime[shit[j] * i] = 0;
if (i % shit[j] == 0)
break;
}
}
}
bool visited[10005];
vector<int> one;
int main() {
//freopen("in.txt", "r", stdin);
init_prime();
int n, k, t;
scanf("%d", &t);
while (t--) {
one.clear();
init();
//cin >> n >> k;
scanf("%d%d", &n, &k);
for (int i = 0; i < n; ++i) {
visited[i] = 0;
scanf("%d", &a[i]);
if (a[i] == 1)
one.push_back(i);
}
int p = 0;
for (int i = 0; i < n; ++i) {
for (int j = i + 1; j < n; ++j) {
if (prime[a[i] + a[j]]) {
if (!visited[i]) {
visited[i] = 1;
++p;
}
if (!visited[j]) {
visited[j] = 1;
++p;
}
if (a[i] == a[j]) {
continue;
}
if (a[i] % 2)
add(i, j);
else
add(j, i);
}
}
}
int temp = min(xyl(n), k);
int res = temp * 2;
p -= res;
//把值为1的点分开讨论。。。写的太恶心了。。自己也不好解释。。
if (temp < k) {
int num = 0;
for (int i = 0; i < one.size(); ++i) {
if (match[one[i]] == -1)
num++;
}
num /= 2;
if (k - temp < num) {
res += (k - temp) * 2;
} else {
k -= temp + num;
p -= num * 2;
res += num * 2 + min(k, p);
}
}
printf("%d\n", res);
}
}