【赛后补题】ccpc2107秦皇岛H题
ZOJ上可以补
赛场上偷听到了隔壁的匈牙利
然后一波操作,未曾想匈牙利之后操作如此复杂
毕竟金牌题,技不如人,甘拜下风
思路: 奇数和偶数分别算作一个集合,二分图构造完毕
烦人的就是那个1,1+1是质数,1+2也是质数,先1内部考虑,然后1+2
(写这段话的时候发现我想错了)
NONONO应该先考虑1+2,再考虑1+1
zoj数据没那么严,不想改了,各位随意
———-吉老师纠正
1+2的在二分图中已经判断了,太好了,我又写了一堆冗余代码,
wtf()
所以剩下的就是,很多很多个1和一堆单身狗们(该说法来自匈牙利算法趣写)
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 3e3 + 7;
//-------------------------prime--------------------------------
const int PRIME_N = 2e6 + 7;
int prime[PRIME_N], primesize;
bool isprime[PRIME_N + 7];
void getprime(int listsize){
memset(isprime, 1, sizeof(isprime));
isprime[1] = false;
primesize = 0;
for(int i=2; i < listsize; i++){
if(isprime[i]) prime[++primesize]=i;
for(int j = 1; j <= primesize && i*prime[j] < listsize; j++){
isprime[i*prime[j]] = false;
if(i%prime[j] == 0) break;
}
}
}
//-------------------------hungary-------------------------------
bool marry[N], adore[N];
int arr[N], boy[N], gir[N], B, G;
struct Hungary{
vector <int> G[N];
bool used[N];// main里面记得memset
int girl[N], n;
inline void init(int _n){
n = _n;
for (int i = 0; i <= n; i++) G[i].clear();
}
inline void addEdge(const int &u, const int &v){
G[u].push_back(v);
}
bool Find(int x){
for (int i = 0; i < G[x].size(); i++){ //扫描每个妹子
int j = G[x][i];
if (used[j]) continue;
// 如果有暧昧并且还没有标记过
// (这里标记的意思是这次查找曾试图改变过该妹子的归属问题,
// 是没有成功,所以就不用瞎费工夫了)
used[j] = 1;
if (girl[j] == 0 || Find(girl[j])) {
//名花无主或者能腾出个位置来,这里使用递归
girl[j] = x;
marry[boy[x]] = marry[gir[j]] = true; // this problem
return true;
}
}
return false;
}
inline int hungary(const int &n){
int all = 0;
memset(girl, 0, sizeof girl);
memset(marry, false, sizeof marry); // this problem
for (int i = 1; i <= n; i++) {
memset(used, 0, sizeof(used)); //这个在每一步中清空
if (Find(i)) all += 1;
}
return all;
}
} hg;
inline int wtf(const int &n, const int &B, const int &k){
int mat = hg.hungary(B);
//printf("mat = %d\n", mat);
if (mat >= k) return k * 2;
int cnt1 = 0, idx = n; // number of one
for (int i = n; i >= 1; i--){
if (arr[i] != 1) {idx = i; break;}
if ((!marry[i])) cnt1++;
marry[i] = true;
}
//printf("cnt1 = %d\n", cnt1);
mat += cnt1 >> 1; // 剩下的1
if (mat >= k) return k*2;
int left = cnt1 & 1; // 单身狗们
for (int i = 1; i <= idx; i++){
left += (!marry[i]) & adore[i];
}
if (mat + left <= k) return mat*2+left;
return mat*2 + (k - mat);
}
int main(){
//freopen("in.txt", "r", stdin);
getprime(2e6 + 7);
int _;
scanf("%d", &_);
for (int n, k; _--;) {
scanf("%d%d", &n, &k);
for (int i = 1; i <= n; i++) scanf("%d", &arr[i]);
sort(arr + 1, arr + n+1, greater<int>());
B = G = 0;
for (int i = 1; i <= n; i++){
if (arr[i] & 1) boy[++B] = i;
else gir[++G] = i;
}
hg.init(B);
memset(adore, false, sizeof adore);
for (int i = 1; i <= B; i++){
for (int j = 1; j <= G; j++){
int num = arr[boy[i]] + arr[gir[j]];
if (isprime[num]) {
hg.addEdge(i, j);
adore[boy[i]] = adore[gir[j]] = true;
}
}
}
int ans = wtf(n, B, k);
printf("%d\n", ans);
}
return 0;
}
吉老师好帅,,,
网络流跑二分图会快很多,
150ms
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 3e3 + 7;
const int INF=0x3f3f3f3f;
//-------------------------prime--------------------------------
const int PRIME_N = 2e6 + 7;
int prime[PRIME_N], primesize;
bool isprime[PRIME_N + 7];
void getprime(int sz){
memset(isprime, 1, sizeof(isprime));
isprime[1] = false;
primesize = 0;
for (int i = 2; i < sz; i++){
if (isprime[i]) prime[++primesize]=i;
for (int j = 1; j <= primesize && i*prime[j] < sz; j++){
isprime[i*prime[j]] = false;
if (i % prime[j] == 0) break;
}
}
}
bool marry[N], adore[N];
int arr[N], boy[N], gir[N], B, G;
//------------------------Dinic-maxFlow--------------------------
struct gragh{
struct Edge{
int from, to, cap, flow;
Edge(int u,int v,int c,int f):from(u),to(v),cap(c),flow(f){}
};
int n, s, t;
vector <Edge> edges;
vector < int> G[N]; //gragh
bool vis[N]; //use when bfs
int d[N],cur[N];//dist,now edge,use in dfs
inline void init(int _n, int _s, int _t){
n = _n; s = _s, t = _t; edges.clear();
for (int i = 0; i <= n; i++) G[i].clear();
}
inline void addEdge(int from, int to, int cap){
edges.push_back(Edge(from,to,cap,0));
edges.push_back(Edge(to,from, 0 ,0));
int top = edges.size();
G[from].push_back(top-2);
G[ to ].push_back(top-1);
}
inline bool BFS(){
memset(vis, 0, sizeof(vis));
queue <int> Q;
d[s]=0;vis[s]=1;
for (Q.push(s); !Q.empty();){
int x = Q.front(); Q.pop();
for (int i = 0; i < G[x].size(); i++){
Edge &e = edges[G[x][i]];
if (vis[e.to] || e.cap <= e.flow)continue;
vis[e.to] = 1;
d[e.to] = d[x] + 1;
Q.push(e.to);
}
}
return vis[t];
}
inline int DFS(const int& x,int a){
//printf("dfs:%d,%d\n",x,a);
if (x==t||a==0){return a;}
int flow = 0, f;
for (int& i = cur[x]; i < G[x].size(); i++){
Edge& e = edges[G[x][i]];
if (d[x] + 1 != d[e.to]) continue;
if ((f=DFS(e.to,min(a,e.cap-e.flow)))<=0)continue;
e.flow += f;
edges[G[x][i]^1].flow -= f;//反向边
flow+=f; a-=f;
marry[x] = marry[e.to] = true;
if (a==0) break;
}
return flow;
}
inline int maxFlow(){return maxFlow(s,t);}
inline int maxFlow(const int& s, const int& t){
//if (edges.size() > N*N>>1) return 233;
int flow = 0;
while (BFS()){
memset(cur, 0, sizeof(cur));
int f = DFS(s, INF);
flow += f ;
}
return flow;
}
} g;
inline int wtf(const int &n, const int &B, const int &k){
memset(marry, false, sizeof marry);
int mat = g.maxFlow();
//printf("mat = %d\n", mat);
if (mat >= k) return k * 2;
int cnt1 = 0, idx = n; // number of one
for (int i = n; i >= 1; i--){
if (arr[i] != 1) {idx = i; break;}
if ((!marry[i])) cnt1++;
marry[i] = true;
}
//printf("cnt1 = %d\n", cnt1);
mat += cnt1 >> 1; // 剩下的1
if (mat >= k) return k*2;
int left = cnt1 & 1; // 单身狗们
for (int i = 1; i <= idx; i++){
left += (!marry[i]) & adore[i];
}
if (mat + left <= k) return mat*2+left;
return mat*2 + (k - mat);
}
int main(){
//freopen("in.txt", "r", stdin);
getprime(2e6 + 7);
int _;
scanf("%d", &_);
for (int n, k; _--;) {
scanf("%d%d", &n, &k);
for (int i = 1; i <= n; i++) scanf("%d", &arr[i]);
sort(arr + 1, arr + n + 1, greater<int>());
B = G = 0;
g.init(n + 1, 0, n + 1);
for (int i = 1; i <= n; i++){
if (arr[i] & 1) {
boy[++B] = i;
g.addEdge(0, i, 1);
} else {
gir[++G] = i;
g.addEdge(i, n+1, 1);
}
}
memset(adore, false, sizeof adore);
for (int i = 1; i <= B; i++){
for (int j = 1; j <= G; j++){
int num = arr[boy[i]] + arr[gir[j]];
if (isprime[num]) {
g.addEdge(boy[i], gir[j], 1);
adore[boy[i]] = adore[gir[j]] = true;
}
}
}
int ans = wtf(n, B, k);
printf("%d\n", ans);
}
return 0;
}
真的是佛了
匈牙利过了,拿前向星版的dinic死活re和wa,找了一年前的vector的dinic板子直接过了,一行一行对,没办法,拿vector的板子现场该前向星,还是狂wa
没错,下面这段代码wa到死,睿智了
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 3e3 + 7;
const int INF = 0x3f3f3f3f;
//-------------------------prime--------------------------------
const int PRIME_N = 2e6 + 7;
int prime[PRIME_N], primesize;
bool isprime[PRIME_N + 7];
void getprime(int listsize){
memset(isprime, 1, sizeof(isprime));
isprime[1] = false;
primesize = 0;
for (int i = 2; i < listsize; i++){
if (isprime[i]) prime[++primesize]=i;
for (int j = 1; j <= primesize && i*prime[j] < listsize; j++){
isprime[i*prime[j]] = false;
if (i % prime[j] == 0) break;
}
}
}
bool marry[N], adore[N];
int arr[N], boy[N], gir[N], B, G;
//------------------------Dinic-maxFlow--------------------------
struct Dinic{
struct Edge{
int from, to, cap, flow, nxt;
Edge(){}
Edge(int u,int v,int c,int f, int n):from(u),to(v),cap(c),flow(f),nxt(n){}
} edges[N*N>>1];
int n, s, t, E, head[N];
bool vis[N]; //use when bfs
int d[N], cur[N]; //dist, now edge, use in dfs
inline void init(int _n, int _s, int _t){
n = _n; s = _s, t = _t; E = 0;
for (int i = 0; i <= n; i++) head[i] = -1;
}
inline void addEdge(int f, int t, int c){
edges[E] = Edge(f, t, c, 0, head[f]);
head[f] = E++;
edges[E] = Edge(t, f, 0, 0, head[t]);
head[t] = E++;
}
inline bool BFS(){
memset(vis, 0, sizeof(vis));
queue <int> Q;
d[s] = 0; vis[s] = 1;
for (Q.push(s); !Q.empty();){
int x = Q.front(); Q.pop();
for (int i = head[x]; ~i; i = edges[i].nxt){
Edge &e = edges[i];
if (vis[e.to] || e.cap <= e.flow) continue;
vis[e.to] = 1;
d[e.to] = d[x] + 1;
Q.push(e.to);
}
}
return vis[t];
}
inline int DFS(const int& x, int a){
//printf("dfs:%d,%d\n",x,a);
if (x == t || a == 0) return a;
int flow = 0, f;
for (int& i = cur[x]; ~i; i = edges[i].nxt){
Edge& e = edges[i];
if (d[x] + 1 != d[e.to]) continue;
if ((f = DFS(e.to,min(a,e.cap-e.flow))) <= 0)continue;
e.flow += f;
edges[i^1].flow-=f;//反向边
flow+=f; a-=f;
marry[x] = marry[e.to] = true;
if (a==0) break;
}
return flow;
}
inline int maxFlow(){return maxFlow(s,t);}
inline int maxFlow(const int& s, const int& t){
int flow = 0;
while (BFS()){
for (int i = 0; i <= n; i++) cur[i] = head[i];
int f = DFS(s, INF);
flow += f ;
}
return flow;
}
} g;
inline int wtf(const int &n, const int &B, const int &k){
memset(marry, false, sizeof marry);
int mat = g.maxFlow();
//printf("mat = %d\n", mat);
if (mat >= k) return k * 2;
int cnt1 = 0, idx = n; // number of one
for (int i = n; i >= 1; i--){
if (arr[i] != 1) {idx = i; break;}
if ((!marry[i])) cnt1++;
marry[i] = true;
}
//printf("cnt1 = %d\n", cnt1);
mat += cnt1 >> 1; // 剩下的1
if (mat >= k) return k*2;
int left = cnt1 & 1; // 单身狗们
for (int i = 1; i <= idx; i++){
left += (!marry[i]) & adore[i];
}
if (mat + left <= k) return mat*2+left;
return mat*2 + (k - mat);
}
int main(){
//freopen("in.txt", "r", stdin);
getprime(2e6 + 7);
int _;
scanf("%d", &_);
for (int n, k; _--;) {
scanf("%d%d", &n, &k);
for (int i = 1; i <= n; i++) scanf("%d", &arr[i]);
sort(arr + 1, arr + n + 1, greater<int>());
B = G = 0;
g.init(n + 1, 0, n + 1);
for (int i = 1; i <= n; i++){
if (arr[i] & 1) {
boy[++B] = i;
g.addEdge(0, i, 1);
} else {
gir[++G] = i;
g.addEdge(i, n+1, 1);
}
}
memset(adore, false, sizeof adore);
for (int i = 1; i <= B; i++){
for (int j = 1; j <= G; j++){
int num = arr[boy[i]] + arr[gir[j]];
if (isprime[num]) {
g.addEdge(boy[i], gir[j], 1);
adore[boy[i]] = adore[gir[j]] = true;
}
}
}
int ans = wtf(n, B, k);
printf("%d\n", ans);
}
return 0;
}