CCPC 2016-2017, Finals Solution
A - The Third Cup is Free
水。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 const int maxn = 1e5 + 10; 6 7 int n; 8 int arr[maxn]; 9 10 int main() 11 { 12 int t; 13 scanf("%d", &t); 14 for(int cas = 1; cas <= t; ++cas) 15 { 16 scanf("%d", &n); 17 for(int i = 1; i <= n; ++i) scanf("%d", arr + i); 18 sort(arr + 1, arr + 1 + n); 19 int ans = 0; 20 int cnt = 0; 21 for(int i = n; i >= 1; --i) 22 { 23 cnt++; 24 if(cnt == 3) 25 { 26 arr[i] = 0; 27 cnt = 0; 28 } 29 ans += arr[i]; 30 } 31 printf("Case #%d: %d\n", cas, ans); 32 } 33 return 0; 34 }
B - Wash
题意:有n个洗衣机,有m个烘干机,要洗L件衣服,最后一件衣服洗完的最少时间
思路:将n个洗衣机扩展成L个洗衣机,将m个烘干机扩展成L个烘干机,那么贪心分配即可。
即用时最少的洗衣机和用时最多的烘干机配对,扩展的话,将n个洗衣机都进堆,然后依次取出,再丢进去,丢进去的时候加上它的洗衣时间即可。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 typedef long long ll; 6 const int maxn = 1e6 + 10; 7 8 struct node{ 9 ll cost, now; 10 node(){} 11 node(ll cost, ll now): cost(cost), now(now){} 12 bool operator < (const node & b) const 13 { 14 return now > b.now; 15 } 16 }; 17 18 int l, n, m; 19 ll arr[maxn]; 20 21 int main() 22 { 23 int t; 24 scanf("%d", &t); 25 for(int cas = 1; cas <= t; ++cas) 26 { 27 scanf("%d %d %d", &l, &n, &m); 28 priority_queue<node>q1, q2; 29 for(int i = 1; i <= n; ++i) 30 { 31 int x; 32 scanf("%d", &x); 33 q1.push(node(x, x)); 34 } 35 for(int i = 1; i <= m; ++i) 36 { 37 int x; 38 scanf("%d", &x); 39 q2.push(node(x, x)); 40 } 41 for(int i = 1; i <= l; ++i) 42 { 43 node tmp = q1.top(); 44 q1.pop(); 45 arr[i] = tmp.now; 46 tmp.now += tmp.cost; 47 q1.push(tmp); 48 } 49 ll ans = 0; 50 for(int i = l; i >= 1; --i) 51 { 52 node tmp = q2.top(); 53 q2.pop(); 54 ans = max(ans, tmp.now + arr[i]); 55 tmp.now += tmp.cost; 56 q2.push(tmp); 57 } 58 printf("Case #%d: %lld\n", cas, ans); 59 } 60 return 0; 61 }
C - Mr.Panda and Survey
留坑。
D - Game Leader
留坑。
E - Problem Buyer
题意:出题人有n道题目,主办方需要m道不同难度题目,出题人的题目有一个难度范围,如果主办方需要买k道题目,那么出题人就从n道题目中随机选取k道给主办方,主办方要使得不论出题人如何给出k道题都能满足他的要求,求最小的k
思路:我们先考虑主办方只需要一道题的情况,答案显然是不符合那道题的其他题目个数+1
那么再考虑推广到m的情况,将区间排序,并且将题目难度也排序,从左至右用优先队列维护里面的区间是否满足,那么不满足的个数就是n - 优先队列里面的元素个数 那么显然对于这道题,至少要取 不满足个数+1 再考虑一个区间只能给一个题目,那么每次扫过去的时候pop出一个即可, $那么我们求出最大的x_i + 1 即可 x_i表示不满足第i个题目的区间有多少个$
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 const int maxn = 1e5 + 10; 6 7 struct node{ 8 int l, r; 9 node(){} 10 node(int l, int r):l(l), r(r){} 11 bool operator < (const node &b)const 12 { 13 return r > b.r; 14 } 15 }arr[maxn]; 16 17 int cmp(node a, node b) 18 { 19 if(a.l == b.l) return a.r > b.r; 20 else return a.l < b.l; 21 } 22 23 int n, m; 24 int brr[maxn]; 25 26 int main() 27 { 28 int t; 29 scanf("%d", &t); 30 for(int cas = 1; cas <= t; ++cas) 31 { 32 scanf("%d %d", &n, &m); 33 for(int i = 1; i <= n; ++i) scanf("%d %d", &arr[i].l, &arr[i].r); 34 for(int i = 1; i <= m; ++i) scanf("%d", brr + i); 35 sort(arr + 1, arr + 1 + n, cmp); 36 sort(brr + 1, brr + 1 + m); 37 priority_queue<node>q; 38 int ans = 0; 39 int j = 1; 40 for(int i = 1; i <= m; ++i) 41 { 42 while(j <= n && arr[j].l <= brr[i]) q.push(arr[j++]); 43 while(!q.empty() && q.top().r < brr[i]) q.pop(); 44 int tmp = q.size(); 45 ans = max(ans, n - tmp + 1); 46 if(ans > n) break; 47 q.pop(); 48 } 49 if(ans > n) printf("Case #%d: IMPOSSIBLE!\n", cas); 50 else printf("Case #%d: %d\n", cas, ans); 51 } 52 return 0; 53 }
F - Periodical Cicadas
留坑。
G - Pandaland
题意:给出一张图,找一个最小环(边权和最小)
思路:枚举每一条边为两个端点跑最短路,如果跑的通即存在环,更新答案即可。
但是正解应该是:
求最小生成树,每次枚举非树边,就是树上两个距离+边权
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define ll long long 5 #define INFLL 0x3f3f3f3f3f3f3f3f 6 #define N 8010 7 #define pii pair <int, int> 8 int t, n, m; 9 map <pii, int> mp; 10 11 struct Edge 12 { 13 struct node 14 { 15 int to, nx, w, vis; 16 node() {} 17 node(int to, int nx, int w, int vis = 1) : to(to), nx(nx), w(w), vis(vis) {} 18 }a[N << 1]; 19 int head[N], pos; 20 void init() { memset(head, 0, sizeof head); pos = -1; } 21 void add(int u, int v, int w) 22 { 23 a[++pos] = node(v, head[u], w); head[u] = pos; 24 a[++pos] = node(u, head[v], w); head[v] = pos; 25 } 26 }G; 27 #define erp(u) for (int it = G.head[u], v = G.a[it].to, w = G.a[it].w; it; it = G.a[it].nx, v = G.a[it].to, w = G.a[it].w) 28 29 int Hash(int x, int y) 30 { 31 if (mp.find(pii(x, y)) == mp.end()) mp[pii(x, y)] = ++n; 32 return mp[pii(x, y)]; 33 } 34 35 struct node 36 { 37 int to; ll w; 38 node () {} 39 node (int to, ll w) : to(to), w(w) {} 40 bool operator < (const node &r) const 41 { 42 return w > r.w; 43 } 44 }; 45 46 ll dist[N]; bool used[N]; 47 48 void Dijkstra(int st, int ed) 49 { 50 for (int i = 1; i <= n; ++i) dist[i] = INFLL, used[i] = false; 51 priority_queue <node> q; q.emplace(st, 0); dist[st] = 0; 52 while (!q.empty()) 53 { 54 int u = q.top().to; q.pop(); 55 if(u == ed) return ; 56 if (used[u]) continue; 57 used[u] = 1; 58 erp(u) if (G.a[it].vis) 59 { 60 if (!used[v] && dist[v] > dist[u] + w) 61 { 62 dist[v] = dist[u] + w; 63 q.emplace(v, dist[v]); 64 } 65 } 66 } 67 } 68 69 int main() 70 { 71 scanf("%d", &t); 72 for (int kase = 1; kase <= t; ++kase) 73 { 74 printf("Case #%d: ", kase); 75 scanf("%d", &m); 76 mp.clear(); n = 0; G.init(); 77 for (int i = 1, x[2], y[2], w, u, v; i <= m; ++i) 78 { 79 for (int j = 0; j < 2; ++j) scanf("%d%d", x + j, y + j); 80 scanf("%d", &w); u = Hash(x[0], y[0]); v = Hash(x[1], y[1]); 81 G.add(u, v, w); 82 } 83 ll res = INFLL; 84 for (int i = 0; i <= m - 1; ++i) 85 { 86 G.a[2 * i].vis = 0; G.a[2 * i + 1].vis = 0; 87 int u = G.a[2 * i].to, v = G.a[2 * i + 1].to; 88 Dijkstra(u, v); 89 res = min(res, G.a[2 * i].w + dist[v]); 90 G.a[2 * i].vis = 1; G.a[2 * i + 1].vis = 1; 91 } 92 if (res == INFLL) res = 0; 93 printf("%lld\n", res); 94 } 95 return 0; 96 }
正解:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define ll long long 5 #define INFLL 0x3f3f3f3f3f3f3f3f 6 #define N 8010 7 #define pii pair <int, int> 8 int t, n, m; 9 map <pii, int> mp; 10 11 struct Gragh 12 { 13 struct node 14 { 15 int to, nx, w; 16 node() {} 17 node(int to, int nx, int w) : to(to), nx(nx), w(w){} 18 }a[N << 1]; 19 int head[N], pos; 20 void init() { memset(head, 0, sizeof head); pos = 0; } 21 void add(int u, int v, int w) 22 { 23 a[++pos] = node(v, head[u], w); head[u] = pos; 24 a[++pos] = node(u, head[v], w); head[v] = pos; 25 } 26 }G; 27 #define erp(u) for (int it = G.head[u], v = G.a[it].to, w = G.a[it].w; it; it = G.a[it].nx, v = G.a[it].to, w = G.a[it].w) 28 29 struct Edge 30 { 31 int u, v, vis; ll w; 32 Edge() {} 33 Edge(int u, int v, ll w, int vis = 0) : u(u), v(v), w(w), vis(vis) {} 34 bool operator < (const Edge &r) const { return w < r.w; } 35 }edge[N]; 36 37 int Hash(int x, int y) 38 { 39 if (mp.find(pii(x, y)) == mp.end()) mp[pii(x, y)] = ++n; 40 return mp[pii(x, y)]; 41 } 42 43 int pre[N]; 44 int find(int x) { return pre[x] == 0 ? x : pre[x] = find(pre[x]); } 45 46 void Kruskal() 47 { 48 sort(edge + 1, edge + 1 + m); 49 for (int i = 1; i <= m; ++i) 50 { 51 int u = edge[i].u, v = edge[i].v; ll w = edge[i].w; 52 int fu = find(u), fv = find(v); 53 if (fu == fv) continue; 54 pre[fu] = fv; 55 G.add(u, v, w); 56 edge[i].vis = 1; 57 } 58 } 59 60 int fa[N], sze[N], son[N], top[N], deep[N], rt[N]; ll dis[N]; 61 void DFS(int u, int root) 62 { 63 sze[u] = 1; 64 rt[u] = root; 65 erp(u) if (v != fa[u]) 66 { 67 fa[v] = u; 68 deep[v] = deep[u] + 1; 69 dis[v] = dis[u] + w; 70 DFS(v, root); sze[u] += sze[v]; 71 if (!son[u] || sze[v] > sze[son[u]]) son[u] = v; 72 } 73 } 74 75 void getpos(int u, int sp) 76 { 77 top[u] = sp; 78 if (!son[u]) return; 79 getpos(son[u], sp); 80 erp(u) if (v != fa[u] && v != son[u]) 81 getpos(v, v); 82 } 83 84 int lca(int u, int v) 85 { 86 while (top[u] != top[v]) 87 { 88 if (deep[top[u]] < deep[top[v]]) swap(u, v); 89 u = fa[top[u]]; 90 } 91 if (deep[u] > deep[v]) swap(u, v); 92 return u; 93 } 94 95 void Init() 96 { 97 mp.clear(); n = 0; G.init(); 98 memset(pre, 0, sizeof pre); 99 memset(son, 0, sizeof son); 100 memset(fa, 0, sizeof fa); 101 } 102 103 int main() 104 { 105 scanf("%d", &t); 106 for (int kase = 1; kase <= t; ++kase) 107 { 108 Init(); 109 printf("Case #%d: ", kase); 110 scanf("%d", &m); 111 for (int i = 1, x[2], y[2], w, u, v; i <= m; ++i) 112 { 113 for (int j = 0; j < 2; ++j) scanf("%d%d", x + j, y + j); 114 scanf("%d", &w); u = Hash(x[0], y[0]); v = Hash(x[1], y[1]); 115 edge[i] = Edge(u, v, w); 116 } Kruskal(); 117 for (int i = 1; i <= n; ++i) if (!fa[i]) 118 { 119 fa[i] = i; dis[i] = 0; deep[i] = 0; 120 DFS(i, i); getpos(i, i); 121 } 122 ll res = INFLL; 123 for (int i = 1, u, v, w; i <= m; ++i) if (!edge[i].vis) 124 { 125 u = edge[i].u, v = edge[i].v, w = edge[i].w; 126 if (rt[u] != rt[v]) continue; 127 res = min(res, dis[u] + dis[v] - 2 * dis[lca(u, v)] + w); 128 } 129 if (res == INFLL) res = 0; 130 printf("%lld\n", res); 131 } 132 return 0; 133 }
H - Engineer Assignment
题意:有b个工程,m个工程师,每个工程师只能分配给一个工程,每个工程师会一些学科,每门工程需要一些学科,一个工程只有当它需要的学科中至少有一个分配到的工程师会,它才能够完成,求如何分配工程师使得完成的工程最多
思路:考虑$s_i$表示一个工程可以完成的工程师组合
$有转移方程 dp[i][j] = max(dp[i][j], dp[i - 1][j - s]) $
$i 表示 第i个工程,j 表示二进制状态 然后 dp 即可$
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 int t, n, m; 5 vector <int> v[20], a[20], b[20]; 6 int cnt[120], dp[20][2048]; 7 8 bool ok(int x) 9 { 10 for (auto it : a[x]) if (!cnt[it]) 11 return false; 12 return true; 13 } 14 15 int main() 16 { 17 scanf("%d", &t); 18 for (int kase = 1; kase <= t; ++kase) 19 { 20 printf("Case #%d: ", kase); 21 scanf("%d%d", &n, &m); 22 for (int i = 1, t; i <= n; ++i) 23 { 24 scanf("%d", &t); 25 a[i].clear(); 26 for (int j = 1, x; j <= t; ++j) 27 { 28 scanf("%d", &x); 29 a[i].push_back(x); 30 } 31 } 32 for (int i = 1, t; i <= m; ++i) 33 { 34 scanf("%d", &t); b[i].clear(); 35 for (int j = 1, x; j <= t; ++j) 36 { 37 scanf("%d", &x); 38 b[i].push_back(x); 39 } 40 } 41 for (int i = 1; i <= n; ++i) 42 { 43 v[i].clear(); 44 for (int j = 1; j < (1 << m); ++j) 45 { 46 memset(cnt, 0, sizeof cnt); 47 for (int k = 0; k < 10; ++k) if ((1 << k) & j) for (auto it : b[k + 1]) 48 cnt[it] = 1; 49 if (ok(i)) v[i].push_back(j); 50 } 51 } 52 int res = 0; 53 memset(dp, 0, sizeof dp); 54 for (int i = 1; i <= n; ++i) 55 { 56 for (int j = 1; j < (1 << m); ++j) for (auto it : v[i]) if ((j & it) == it) 57 dp[i][j] = max(dp[i][j], dp[i - 1][j - it] + 1), res = max(res, dp[i][j]); 58 for (int j = 1; j < (1 << m); ++j) dp[i][j] = max(dp[i][j], dp[i - 1][j]); 59 } 60 printf("%d\n", res); 61 } 62 return 0; 63 }
I - Mr. Panda and Crystal
题意:有n种物品,有的物品可以直接生成,有的可以不生成,需要合成,会给出一个合成方程,每种物品有价值,有一个容量为m的背包,求装下哪些物品使得价值最大
思路:最短路求出每个物品的最小生成成本,再做完全背包即可。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define ll long long 5 #define N 40010 6 #define INFLL 0x3f3f3f3f3f3f3f3f 7 #define pii pair <int, int> 8 int t, m, n, k; 9 ll v[N], dp[N]; 10 11 struct EXP 12 { 13 int to; 14 vector <pii> v; 15 }ex[N]; 16 vector <int> G[N]; 17 18 struct node 19 { 20 int to; ll w; 21 node () {} 22 node (int to, ll w) : to(to), w(w) {} 23 bool operator < (const node &r) const { return w > r.w; } 24 }; 25 26 ll dist[N]; bool used[N]; 27 void Dijkstra() 28 { 29 priority_queue <node> q; 30 for (int i = 1; i <= n; ++i) if (dist[i] != INFLL) q.emplace(i, dist[i]); 31 while (!q.empty()) 32 { 33 int u = q.top().to; q.pop(); 34 if (used[u]) continue; 35 used[u] = 1; 36 for (auto it : G[u]) 37 { 38 ll tmp = 0; 39 for (auto it2 : ex[it].v) 40 { 41 int to = it2.first, w = it2.second; 42 if (dist[to] == INFLL) 43 { 44 tmp = INFLL; 45 break; 46 } 47 else 48 tmp += dist[to] * w; 49 } 50 int v = ex[it].to; 51 if (!used[v] && dist[v] > tmp) 52 { 53 dist[v] = tmp; 54 q.emplace(v, dist[v]); 55 } 56 } 57 } 58 } 59 60 int main() 61 { 62 scanf("%d", &t); 63 for (int kase = 1; kase <= t; ++kase) 64 { 65 printf("Case #%d: ", kase); 66 scanf("%d%d%d", &m, &n, &k); 67 for (int i = 1; i <= n; ++i) dist[i] = INFLL, used[i] = 0; 68 for (int i = 1, vis; i <= n; ++i) 69 { 70 scanf("%d", &vis); if (vis) scanf("%lld", dist + i); 71 scanf("%lld", v + i); 72 G[i].clear(); 73 } 74 for (int i = 1, t; i <= k; ++i) 75 { 76 scanf("%d", &ex[i].to); ex[i].v.clear(); 77 scanf("%d", &t); 78 for (int j = 1, x, y; j <= t; ++j) 79 { 80 scanf("%d%d", &x, &y); 81 ex[i].v.push_back(pii(x, y)); 82 G[x].push_back(i); 83 } 84 } 85 Dijkstra(); 86 memset(dp, 0, sizeof dp); 87 for (int i = 1; i <= n; ++i) 88 { 89 for (int j = dist[i]; j <= m; ++j) 90 dp[j] = max(dp[j], dp[j - dist[i]] + v[i]); 91 } 92 printf("%lld\n", dp[m]); 93 } 94 return 0; 95 }
J - Worried School
水。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 int t, g; string tar; 5 set <string> se; 6 string s[6][100]; 7 8 void work() 9 { 10 for (int i = 1; i <= 20; ++i) 11 { 12 for (int j = 0; j < 5; ++j) 13 { 14 if (s[j][i] == tar) return; 15 se.insert(s[j][i]); 16 } 17 } 18 } 19 20 void work2() 21 { 22 for (int i = 1; i <= 20; ++i) 23 { 24 if (s[5][i] == tar) return; 25 se.insert(s[5][i]); 26 } 27 } 28 29 int main() 30 { 31 ios::sync_with_stdio(false); 32 cin.tie(0); 33 cout.tie(0); 34 cin >> t; 35 for (int kase = 1; kase <= t; ++kase) 36 { 37 cout << "Case #" << kase << ": "; 38 cin >> g >> tar; 39 se.clear(); 40 for (int i = 0; i < 6; ++i) for (int j = 1; j <= 20; ++j) cin >> s[i][j]; 41 work(); 42 if (se.size() >= g) 43 { 44 cout << "0\n"; 45 continue; 46 } 47 int res = g - (int)se.size(); 48 work2(); 49 if (se.size() < g) cout << "ADVANCED!\n"; 50 else cout << max(0, res) << "\n"; 51 } 52 return 0; 53 }
K - Lazors
留坑。
L - Daylight Saving Time
按题意模拟即可。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 struct node 5 { 6 int h, m, s; 7 node () {} 8 node (int h, int m, int s) : h(h), m(m), s(s) {} 9 }a; 10 int t, Year, Mon, Day; 11 int num[2][13] = 12 { 13 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 14 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 15 }; 16 17 int ok(int x) 18 { 19 if ((x % 4 == 0 && x % 100 != 0) || x % 400 == 0) return 1; 20 return 0; 21 } 22 23 int calc(int y, int m, int d) 24 { 25 int res = 0; 26 for (int i = 2007; i < y; ++i) 27 res += 365 + ok(i); 28 for (int i = 1; i < m; ++i) res += num[ok(y)][i]; 29 res += d; 30 return (res - 1) % 7 + 1; 31 } 32 33 int main() 34 { 35 scanf("%d", &t); 36 for (int kase = 1; kase <= t; ++kase) 37 { 38 printf("Case #%d: ", kase); 39 scanf("%04d-%02d-%02d %02d:%02d:%02d", &Year, &Mon, &Day, &a.h, &a.m, &a.s); 40 if (Mon == 3) 41 { 42 int tar = 15 - calc(Year, 3, 1); 43 if (Day == tar) 44 { 45 if (a.h == 2) puts("Neither"); 46 else if (a.h < 2) puts("PST"); 47 else puts("PDT"); 48 } 49 else puts(Day < tar ? "PST" : "PDT"); 50 } 51 else if (Mon == 11) 52 { 53 int tar = 8 - calc(Year, 11, 1); 54 if (Day == tar) 55 { 56 if (a.h == 1) puts("Both"); 57 else if (a.h < 1) puts("PDT"); 58 else puts("PST"); 59 } 60 else puts(Day < tar ? "PDT" : "PST"); 61 } 62 else puts(Mon < 3 ? "PST" : "PDT"); 63 } 64 return 0; 65 }