题目链接:http://codeforces.com/contest/808/problem/F
题意:给出n个三元组,和一个整数k。包括三个属性p c l。要求选出的几个三元组满足∑pi>=k,并且还要满足:
选出的任意两个ci+cj不是素数。
额外有一个变量lv,不能选择li > lv的三元组。
求这个lv的最小值是多少,可以满足上述条件。
转换成二分图来做,考虑奇数和奇数的和为偶数,必然不是素数;偶数和偶数的和为偶数,必然不是素数。所以我们可以按照奇偶来区分点,这样就不用拆点了。
相当于是以两点权值和为素数的条件下的最大点权独立集,希望找到这么一个点集,使他们没有边相连(和不是素数)。
结果就WA了,为什么呢?
看了tutorial才知道,假如有多个1存在,会破坏这个二分图的性质。因为>=2的时候,1被分在奇数侧,而实际上可以选2个1构成一个素数,显然不符合条件。
所以最多只能有一个1,有的话,贪心地选p最大的那个就行。
根据定理,最大点券独立集=点权和-最小割。
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int maxm = 500000; 5 const int maxn = 2010; 6 const int inf = 0x7f7f7f7f; 7 8 typedef struct Edge { int u, v, w, next; }Edge; 9 bool isprime[maxm]; 10 int prime[maxm]; 11 int pcnt; 12 int cnt, dhead[maxn]; 13 int cur[maxn], dd[maxn]; 14 Edge dedge[maxm]; 15 int S, T, N; 16 17 void getPrime() { 18 memset(isprime, true, sizeof(isprime)); 19 memset(prime, 0, sizeof(prime)); 20 pcnt = 0; 21 prime[0] = prime[1] = 0; 22 for(int i = 2; i <= maxm; i++) { 23 if(isprime[i]) prime[++pcnt] = i; 24 for(int j = 1; j <= pcnt; j++) { 25 if(i * prime[j] > maxm) break; 26 isprime[i*prime[j]] = 0; 27 if(i % prime[j] == 0) break; 28 } 29 } 30 } 31 32 void init() { 33 memset(dhead, -1, sizeof(dhead)); 34 for(int i = 0; i < maxn; i++) dedge[i].next = -1; 35 S = T = N = 0; cnt = 0; 36 } 37 38 void adde(int u, int v, int w, int c1=0) { 39 dedge[cnt].u = u; dedge[cnt].v = v; dedge[cnt].w = w; 40 dedge[cnt].next = dhead[u]; dhead[u] = cnt++; 41 dedge[cnt].u = v; dedge[cnt].v = u; dedge[cnt].w = c1; 42 dedge[cnt].next = dhead[v]; dhead[v] = cnt++; 43 } 44 45 bool bfs(int s, int t, int n) { 46 queue<int> q; 47 for(int i = 0; i < n; i++) dd[i] = inf; 48 dd[s] = 0; 49 q.push(s); 50 while(!q.empty()) { 51 int u = q.front(); q.pop(); 52 for(int i = dhead[u]; ~i; i = dedge[i].next) { 53 if(dd[dedge[i].v] > dd[u] + 1 && dedge[i].w > 0) { 54 dd[dedge[i].v] = dd[u] + 1; 55 if(dedge[i].v == t) return 1; 56 q.push(dedge[i].v); 57 } 58 } 59 } 60 return 0; 61 } 62 63 int dinic(int s, int t, int n) { 64 int st[maxn], top; 65 int u; 66 int flow = 0; 67 while(bfs(s, t, n)) { 68 for(int i = 0; i < n; i++) cur[i] = dhead[i]; 69 u = s; top = 0; 70 while(cur[s] != -1) { 71 if(u == t) { 72 int tp = inf; 73 for(int i = top - 1; i >= 0; i--) { 74 tp = min(tp, dedge[st[i]].w); 75 } 76 flow += tp; 77 for(int i = top - 1; i >= 0; i--) { 78 dedge[st[i]].w -= tp; 79 dedge[st[i] ^ 1].w += tp; 80 if(dedge[st[i]].w == 0) top = i; 81 } 82 u = dedge[st[top]].u; 83 } 84 else if(cur[u] != -1 && dedge[cur[u]].w > 0 && dd[u] + 1 == dd[dedge[cur[u]].v]) { 85 st[top++] = cur[u]; 86 u = dedge[cur[u]].v; 87 } 88 else { 89 while(u != s && cur[u] == -1) { 90 u = dedge[st[--top]].u; 91 } 92 cur[u] = dedge[cur[u]].next; 93 } 94 } 95 } 96 return flow; 97 } 98 99 int n, k; 100 int p[maxn], c[maxn], l[maxn]; 101 102 int gao(int lv) { 103 init(); 104 S = 0; T = n + 1; N = T + 1; 105 int tot = 0; 106 int id, mx = -inf; 107 for(int i = 1; i <= n; i++) { 108 if(l[i] > lv) continue; 109 if(c[i] == 1 && p[i] > p[id]) id = i; 110 } 111 for(int i = 1; i <= n; i++) { 112 if(l[i] > lv) continue; 113 if(c[i] == 1 && i != id) continue; 114 tot += p[i]; 115 if(c[i] & 1) adde(S, i, p[i]); 116 else adde(i, T, p[i]); 117 } 118 for(int i = 1; i <= n; i++) { 119 for(int j = 1; j <= n; j++) { 120 if(isprime[c[i]+c[j]]) { 121 if(c[i] & 1) adde(i, j, inf); 122 else adde(j, i, inf); 123 } 124 } 125 } 126 return tot - dinic(S, T, N) >= k; 127 } 128 129 int main() { 130 // freopen("in", "r", stdin); 131 getPrime(); 132 while(~scanf("%d%d",&n,&k)) { 133 int mx = -1; 134 for(int i = 1; i <= n; i++) { 135 scanf("%d%d%d",&p[i],&c[i],&l[i]); 136 mx = max(mx, l[i]); 137 } 138 int lo = 1, hi = mx; 139 int ret = -1; 140 while(lo <= hi) { 141 int mid = (lo + hi) >> 1; 142 if(gao(mid)) { 143 ret = mid; 144 hi = mid - 1; 145 } 146 else lo = mid + 1; 147 } 148 printf("%d ", ret); 149 } 150 return 0; 151 }