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;
}

最新文章

  1. linux查看是什么操作系统是什么命令
  2. CSS padding margin border属性详解
  3. AngularJs中,如何在render完成之后,执行Js脚本
  4. ObjectStateManager 中已存在具有同一键的对象。ObjectStateManager 无法跟踪具有相同键的多个对象。
  5. 关于阿里 阿里巴巴共享业务事业部UED团队 出品的sui基于zepto的开源UI框架的使用心得
  6. 安卓App和java通信实例
  7. C#:通过Visual Studio项目预生成命令获取SVN版本号
  8. 客户端cmd打开mysql,执行插入中文报错或插入中文乱码解决方案
  9. sublime text2 解决中文乱码
  10. anible包模块管理
  11. 简约之美Jodd-http--应用一箩筐
  12. 再识C中的结构体
  13. 在Linux-0.11中实现基于内核栈切换的进程切换
  14. ios开发 block语句块
  15. 多个线程怎样操作同一个epoll fd
  16. java代码中init method和destroy method的三种使用方式
  17. WINCE的批处理
  18. RabbitMQ消息队列(五)-安装amqp扩展并订阅/发布Demo(.Net Core版)
  19. ionic3 生成android 如何控制versionCode版本号
  20. Android 项目中文件夹作用(res文件夹详细介绍)

热门文章

  1. LeetCode--Remove Linked List Element
  2. Windows查看进程CMD命令和终止进程CMD命令
  3. hdu 6203 ping ping ping(LCA+树状数组)
  4. Jsp上传组件Smartupload介绍
  5. 【ZJ选讲&#183;压缩】
  6. 初识 spl_autoload_register
  7. jquery.cookie.js 的使用指南
  8. JavaScript中cookie使用
  9. 前端面试:什么是css reset
  10. HibernateException: Unable to instantiate default tuplizer [org.hibernate.tuple.entity.PojoEntityTup