Educational Codeforces Round 21 Problem F (Codeforces 808F) - 最小割 - 二分答案

Posted 阿波罗2003

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Educational Codeforces Round 21 Problem F (Codeforces 808F) - 最小割 - 二分答案相关的知识,希望对你有一定的参考价值。

Digital collectible card games have become very popular recently. So Vova decided to try one of these.

Vova has n cards in his collection. Each of these cards is characterised by its power pi, magic number ci and level li. Vova wants to build a deck with total power not less than k, but magic numbers may not allow him to do so — Vova can‘t place two cards in a deck if the sum of the magic numbers written on these cards is a prime number. Also Vova cannot use a card if its level is greater than the level of Vova‘s character.

At the moment Vova‘s character‘s level is 1. Help Vova to determine the minimum level he needs to reach in order to build a deck with the required total power.

Input

The first line contains two integers n and k (1 ≤ n ≤ 100, 1 ≤ k ≤ 100000).

Then n lines follow, each of these lines contains three numbers that represent the corresponding card: pici and li(1 ≤ pi ≤ 1000, 1 ≤ ci ≤ 100000, 1 ≤ li ≤ n).

Output

If Vova won‘t be able to build a deck with required power, print  - 1. Otherwise print the minimum level Vova has to reach in order to build a deck.

Examples
input
5 8
5 5 1
1 5 4
4 6 3
1 12 4
3 12 1
output
4
input
3 7
4 4 1
5 8 2
5 3 3
output
2

  题目大意是说,每个物品有三个属性p,c, l,当等级大于等于l才可已使用这个物品,选出一些物品使得两两的c之和为合数且p之和大于等于k,并且其中最大的l尽可能小,求这个最小需要达到的等级,如果无解,输出-1。

  通过最大值中的最小值可以想到二分答案,然后考虑用网络流得到最大的p值和。

  我的建图有点麻烦,但是是我自己想出来的。每个物品连源点,再弄n个点,连汇点,第i + 1个点和第(i + n + 1)个点(第一个点是源点)容量为第i个物品的价值。如果说第i个物品和第j个物品和为质数,就连一条i到j的边,容量为无限大(inf)。割掉于源点相连的边的意义就是不选这个物品,但是由于这个图"对称",所以与汇点相连的对应的边也会被割掉。所以最大的p值和为 当前可选物品p值和 - (最小割容量 / 2)。

  至于这个判素数,反正我残暴地用欧拉筛打表,用费马小定理应该会快一些。

Code(这代码长度可以和树套树媲美了,绝望。。)

  1 /**
  2  * Codeforces
  3  * Problem#808F
  4  * Accepted
  5  * Time:62ms
  6  * Memory:10300k
  7  */ 
  8 #include <iostream>
  9 #include <cstdio>
 10 #include <ctime>
 11 #include <cmath>
 12 #include <cctype>
 13 #include <cstring>
 14 #include <cstdlib>
 15 #include <fstream>
 16 #include <sstream>
 17 #include <algorithm>
 18 #include <map>
 19 #include <set>
 20 #include <stack>
 21 #include <queue>
 22 #include <vector>
 23 #include <stack>
 24 #ifndef WIN32
 25 #define Auto "%lld"
 26 #else
 27 #define Auto "%I64d"
 28 #endif
 29 using namespace std;
 30 typedef bool boolean;
 31 const signed int inf = (signed)((1u << 31) - 1);
 32 #define smin(a, b) a = min(a, b)
 33 #define smax(a, b) a = max(a, b)
 34 #define max3(a, b, c) max(a, max(b, c))
 35 #define min3(a, b, c) min(a, min(b, c))
 36 template<typename T>
 37 inline boolean readInteger(T& u){
 38     char x;
 39     int aFlag = 1;
 40     while(!isdigit((x = getchar())) && x != - && x != -1);
 41     if(x == -1) {
 42         ungetc(x, stdin);
 43         return false;
 44     }
 45     if(x == -){
 46         x = getchar();
 47         aFlag = -1;
 48     }
 49     for(u = x - 0; isdigit((x = getchar())); u = (u << 1) + (u << 3) + x - 0);
 50     ungetc(x, stdin);
 51     u *= aFlag;
 52     return true;
 53 }
 54 
 55 ///map template starts
 56 typedef class Edge{
 57     public:
 58         int end;
 59         int next;
 60         int flow;
 61         int cap;
 62         int lvl;
 63         Edge(int end = 0, int next = 0, int flow = 0, int cap = 0, int lvl = 0):end(end), next(next), flow(flow), cap(cap), lvl(lvl) {    }
 64 }Edge;
 65 
 66 typedef class MapManager{
 67     public:
 68         int ce;
 69         int *h;
 70         Edge *edge;
 71         MapManager() {    }
 72         MapManager(int points, int limit):ce(0) {
 73             h = new int[(const int)(points + 1)];
 74             edge = new Edge[(const int)(limit + 1)];
 75             memset(h, 0, sizeof(int) * (points + 1));
 76         }
 77         
 78         inline void addEdge(int from, int end, int flow, int cap, int lvl) {
 79             edge[++ce] = Edge(end, h[from], flow, cap, lvl);
 80             h[from] = ce;
 81         }
 82         
 83         inline void addDoubleEdge(int from, int end, int cap, int lvl) {
 84             addEdge(from, end, 0, cap, lvl);
 85             addEdge(end, from, cap, cap, lvl);
 86         }
 87         
 88         Edge& operator [] (int pos) {
 89             return edge[pos];
 90         }
 91         
 92         inline int reverse(int i) {
 93             return (i & 1) ? (i + 1) : (i - 1);
 94         }
 95         
 96         inline void clone(MapManager& g, int n) {
 97             g.ce = ce;
 98             memcpy(g.h, h, sizeof(int) * (n + 1));
 99             memcpy(g.edge, edge, sizeof(Edge) * (ce + 1));
100         }
101 }MapManager;
102 #define m_begin(g, i) (g).h[(i)]
103 ///map template ends
104 
105 int n, m;
106 int csum = 0;
107 int *ps, *cs, *ls;
108 inline void init() {
109     readInteger(n);
110     readInteger(m);
111     ps = new int[(const int)(n + 1)];
112     cs = new int[(const int)(n + 1)];
113     ls = new int[(const int)(n + 1)];
114     for(int i = 1; i <= n; i++) {
115         readInteger(cs[i]);
116         readInteger(ps[i]);
117         readInteger(ls[i]);
118         csum += ps[i];
119     }
120 }
121 
122 int num = 0;
123 int pri[500000];
124 boolean* vis;
125 inline void Euler() {
126     vis = new boolean[(const int)(csum + 1)];
127     memset(vis, false, sizeof(boolean) * (csum + 1));
128     vis[1] = true;
129     for(int i = 2; i <= csum; i++) {
130         if(!vis[i]) pri[++num] = i;
131         for(int j = 1; j <= num; j++) {
132             long long x = pri[j] * 1LL * i;
133             if(x > csum)    break;
134             vis[x] = true;
135             if((i % pri[j]) == 0)    break;
136         }
137     }
138 }
139 
140 int s, t;
141 MapManager g;
142 MapManager mg;
143 inline void init_map() {
144     s = 0, t = 2 * n + 1;
145     g = MapManager(2 * n + 1, 4 * n * n);
146     mg = MapManager(2 * n + 1, 4 * n * n);
147     for(int i = 1; i <= n; i++) {
148         mg.addDoubleEdge(s, i, cs[i], ls[i]);
149         mg.addDoubleEdge(i + n, t, cs[i], ls[i]);
150 //        if(!vis[ps[i]])
151 //            mg.addDoubleEdge(i, i + n, cs[i], ls[i]);
152         for(int j = i + 1; j <= n; j++) {
153             if(!vis[ps[i] + ps[j]]) {
154                 mg.addDoubleEdge(i, j + n, inf, 0);
155                 mg.addDoubleEdge(j, i + n, inf, 0);
156             }
157         }
158     }
159     delete[] vis;
160 }
161 
162 int* dis;
163 queue<int> que;
164 inline boolean bfs(int mid) {
165     memset(vis, false, sizeof(boolean) * (t + 1));
166     que.push(s);
167     vis[s] = true;
168     dis[s] = 0;
169     while(!que.empty()) {
170         int e = que.front();
171         que.pop();
172         for(int i = m_begin(g, e); i; i = g[i].next) {
173             if(g[i].lvl > mid)    continue;
174             if(g[i].cap == g[i].flow)    continue;
175             int eu = g[i].end;
176             if(vis[eu])    continue;
177             vis[eu] = true;
178             dis[eu] = dis[e] + 1;
179             que.push(eu);
180         }
181     }
182     return vis[t];
183 }
184 
185 int *cur;
186 inline int blockedflow(int node, int minf, int& mid) {
187     if((node == t) || (minf == 0))    return minf;
188     int f, flow = 0;
189     for(int& i = cur[node]; i; i = g[i].next) {
190         int& eu = g[i].end;
191         if(g[i].lvl <= mid && dis[eu] == dis[node] + 1 && g[i].flow < g[i].cap && (f = blockedflow(eu, min(minf, g[i].cap - g[i].flow), mid)) > 0) {
192             minf -= f;
193             flow += f;
194             g[i].flow += f;
195             g[g.reverse(i)].flow -= f;
196             if(minf == 0)    return flow;
197         }
198     }
199     return flow;
200 }
201 
202 inline void init_dinic() {
203     vis = new boolean[(const int)(t + 1)];
204     dis = new int[(const int)(t + 1)];
205     cur = new int[(const int)(t + 1)];
206 }
207 
208 inline int dinic(int mid) {
209     int maxflow = 0;
210     int cc = 0;
211     mg.clone(g, t);
212     for(int i = 1; i <= n; i++)
213         if(ls[i] <= mid)
214             cc += cs[i];
215     if(cc < m)
216         return cc;
217     while(bfs(mid)) {
218         for(int i = 0; i <= t; i++)
219             cur[i] = m_begin(g, i);
220         maxflow += blockedflow(s, inf, mid);
221     }
222     return cc - (maxflow >> 1);
223 }
224 
225 inline void solve() {
226     int l = 1, r = n;
227     while(l <= r) {
228         int mid = (l + r) >> 1;
229         if(dinic(mid) < m)    l = mid + 1;
230         else r = mid - 1;
231     }
232     if(r == n)    puts("-1");
233     else printf("%d", r + 1);
234 }
235 
236 int main() {
237     init();
238     Euler();
239     init_map();
240     init_dinic();
241     solve();
242     return 0;
243 }

 

以上是关于Educational Codeforces Round 21 Problem F (Codeforces 808F) - 最小割 - 二分答案的主要内容,如果未能解决你的问题,请参考以下文章

Educational Codeforces Round 7 A

Educational Codeforces Round 7

Educational Codeforces Round 90

Educational Codeforces Round 33

Codeforces Educational Codeforces Round 54 题解

Educational Codeforces Round 27