zoj3988
zoj3988
题意
如果一个集合 \(\{i,j\}\) 满足 \(i\neq j\) 且 \(a[i]+a[j]\) 是素数,则称之为素数集合。
给出一些数字,这些数字可以组成多种素数集合,从这些集合中最多选择 \(k\) 个集合,问这些集合涉及到的数的数量最大值为多少。
分析
存在匹配关系即 \(a[i]+a[j]\) 是素数,那么 \(i\) \(j\) 就可以连边,要求两个数的和为素数,那么这两个数一定有一奇数一偶数(也有可能两个 \(1\)),将奇数放左边,偶数放右边,建二分图。求一发二分图匹配即可。
要注意的是两个 1 的和也是素数,首先奇数 1 放在最后不急着匹配,如果 \(1\) 的数量大于 \(1\) 的话,先将两个 \(1\) 组合起来。
code
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N = 2e6 + 10;
const int MAXN = 3e3 + 5;
int notprime[N];
int n, k;
vector<int> odd, even;
int vis[MAXN], has[MAXN], a[MAXN], b[MAXN];
vector<int> v[MAXN];
int dfs(int x) {
for(int i = 0; i < v[x].size(); i++) {
int to = v[x][i];
if(!vis[to]) {
vis[to] = 1;
if(has[to] == -1 || dfs(has[to])) {
has[to] = x;
return 1;
}
}
}
return 0;
}
int main() {
for(int i = 2; i < N; i++) if(!notprime[i]) {
for(ll j = 1LL * i * i; j < N; j += i) notprime[j] = 1;
}
int T;
scanf("%d", &T);
while(T--) {
odd.clear();
even.clear();
memset(has, -1, sizeof has);
scanf("%d%d", &n, &k);
int cnt = 0;
for(int i = 0; i < n; i++) {
int x;
scanf("%d", &x);
if(x == 1) cnt++;
else if(x & 1) odd.push_back(x);
else even.push_back(x);
}
int cc = cnt;
while(cc--) odd.push_back(1);
int ans = 0;
for(int i = 0; i < odd.size(); i++) {
v[i].clear();
for(int j = 0; j < even.size(); j++) {
if(!notprime[odd[i] + even[j]]) {
v[i].push_back(j);
}
}
memset(vis, 0, sizeof vis);
if(dfs(i) && k) {
ans += 2;
k--;
}
}
memset(a, 0, sizeof a);
memset(b, 0, sizeof b);
for(int i = 0; i < even.size(); i++) {
if(has[i] != -1) {
a[has[i]] = 1;
b[i] = 1;
}
}
int cnt1 = 0;
for(int i = 0; i < odd.size() && k; i++) {
if(!a[i] && odd[i] == 1) cnt1++;
}
while(k && cnt1 > 1) {
cnt1 -= 2;
ans += 2;
k--;
}
int flg = cnt1;
for(int i = 0; i < odd.size() && k; i++) {
if(!a[i] && odd[i] == 1) {
if(flg) {
flg--;
} else {
a[i] = 1;
}
}
}
for(int i = 0; i < odd.size() && k; i++) {
for(int j = 0; j < v[i].size() && k; j++) {
int to = v[i][j];
if(a[i] && !b[to]) { ans++; k--; b[to] = 1; }
else if(!a[i] && b[to]) { ans++; k--; if(odd[i] == 1) cnt1--; a[i] = 1; }
}
}
if(k && cnt > 1 && cnt1) ans++;
printf("%d\n", ans);
}
return 0;
}
zoj3988的更多相关文章
- 2017CCPC秦皇岛 H题Prime Set&&ZOJ3988
题意: 定义一种集合,只有两个数,两个数不同且加起来为素数.要从n个数里抽出数字组成该集合(数字也可以是1~n,这个好懵圈啊),要求你选择最多k个该种集合组成一个有最多元素的集合,求出元素的数量. 思 ...
- 【二分图最大匹配】【匈牙利算法】zoj3988 Prime Set
题意:给你n个正整数,一对和为素数的数为一个合法数对.你选不超过K个合法数对,使得你选的数对涉及到的数的数量最大化.输出这个值. 所有1之间是可以任意两两配对的. 把奇数放在左侧,偶数放在右侧. 考虑 ...
- zoj3988 二分图匹配
给一个数组,对于每两个数加起来为素数那么就是一个集合,求不超过k个集合的最多数是多少 解法:二分图匹配,先打素数筛,预处理边集,匹配完之后分两种情况k>匹配数,那么可以直接输出匹配数*2,否则可 ...
- zoj3988 Prime Set
思路不难想到二分图求个最大匹配P,若P>=K,则2*K即可,否则应为P*2+min(K-P,未匹配且有度数不为0的顶点个数s).但坑点在于有1的情况,所以如果直接建二分图去跑最大匹配会因为1的影 ...
- ZOJ-3988 2017CCPC-秦皇岛 Prime Set 二分图最大匹配 匈牙利
题面 题意:给你n个数,你可以选择2个和为质数的数为一对,每个数可以重复选择,你最多选k对,问你最多能选多少个不同数出来 题解:首先思考怎么样的数和为质数,2个偶数相加不行,除了1+1以外2个奇数相加 ...
随机推荐
- json解析之jackson
对于json格式的数据解析现在越来越多了,之前介绍了两种:fastjson和net.sf.json解析. 今天又有一个jackson解析.不过相对于之前两种,这种感觉稍微笨拙些.呵呵,还是了解下吧: ...
- es6+最佳入门实践(11)
11.async函数 async 函数是什么?一句话,它就是 Generator 函数的语法糖.通俗的说就是Generator函数的另一种写法,这种写法更简洁,除此之外,async函数还对Genrat ...
- Python基础(1)_初识Python
一.为什么要编程 解放人力:让机器按照人们事先为其编写好的程序自发地去工作 二.什么是编程语言 编程语言就是程序员与计算机之间沟通的介质:程序员把自己想说的话用编程语言写到文件里,这其实就开发了一个程 ...
- bzoj4128 Matrix
传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4128 [题解] 矩阵版本的BSGS. 至于如何不需要求逆,详见:http://www.cnb ...
- bzoj4602 [Sdoi2016]齿轮
传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4602 [题解] 对于每组齿轮(u, v)连边,权值为y/x(反向边x/y) 那么直接dfs计 ...
- 51nodeE 斜率最大
题目传送门 这道题只要证明最佳解一定在相邻两个点之间的好啦 这个自己证一证就okay啦 而且我发现n方的算法可以过耶... #include<cstdio> #include<cst ...
- [bzoj2124]等差子序列——线段树+字符串哈希
题目大意 给一个1到N的排列\(A_i\),询问是否存在\(p_i\),\(i>=3\),使得\(A_{p_1}, A_{p_2}, ... ,A_{p_len}\)是一个等差序列. 题解 显然 ...
- xampp命令
XAMPP命令安装 XAMPPtar xvfz xampp-linux-1.6.4.tar.gz -C /opt启动 XAMPP/opt/lampp/lampp start停止 XAMPP/opt/l ...
- 转:SWT中的Display 对象和 Shell对象
转自: http://blog.csdn.net/chulaixi/article/details/3095478 我们书写swt程序的步骤,这些步骤是: 1. 创建一个Display对象 2. 创建 ...
- IPC网络高清摄像机基础知识4(Sensor信号输出YUV、RGB、RAW DATA、JPEG 4种方式区别) 【转】
转自:http://blog.csdn.net/times_poem/article/details/51682785 [-] 一 概念介绍 二 两个疑问 三 RAW和JPEG的区别 1 概念说明 3 ...