ACM-ICPC SouthWestern Europe Regional Contest 2017题解
Posted zkin
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ACM-ICPC SouthWestern Europe Regional Contest 2017题解相关的知识,希望对你有一定的参考价值。
题目地址
http://codeforces.com/gym/101635/
A 题:
计算两个数组元素之间最有可能的差值,注意数据全部非法时的情况
#include<bits/stdc++.h> using namespace std; const int maxn = 2005; int a[maxn], b[maxn]; int main() { int n, m; scanf("%d%d", &n, &m); unordered_map<int, int> mp; for (int i = 0; i < n; ++i) { scanf("%d", a + i); } for (int i = 0; i < m; ++i) { scanf("%d", b + i); for (int j = 0; j < n; ++j) { if (a[j] > b[i]) break; ++mp[b[i] - a[j]]; } } int max_num = 0, max_cnt = 0; for (auto i : mp) { if (max_cnt < i.second || max_cnt == i.second && i.first < max_num) { max_cnt = i.second; max_num = i.first; } } printf("%d ", max_num); return 0; }
B 题:
C题:
用1*2 或者 1 * 1的矩形块覆盖n * m的矩形,求出所有可能的摆放方式总数(mod 1e9),通过状压DP计算n = 1 ~ 8条件下的递推式f(n),根据递推式运用矩阵快速幂计算出F(n)的值
D题:
E题:
给出一个菜谱的有向无环图,有每种菜的花费以及这种菜所依赖的菜的花费和价值,要求最终的菜单中每种菜只能出现一次,问在花费不超过B的前提下,价值和最大。
一种菜的合成受限于另一种菜,容易想到拓扑排序,根据拓扑排序的性质,可以得到每种菜最小的合成代价,然后01背包即可
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn = 1e6 + 7; 4 typedef long long ll; 5 const int inf = 0x3f3f3f3f; 6 char s1[maxn][25]; 7 char s2[maxn][25]; 8 char s3[maxn][25]; 9 int c[maxn]; 10 int v[maxn]; 11 int cc[maxn]; 12 int vv[maxn]; 13 int in[maxn]; 14 int sta[maxn]; 15 map<string, int>mp; 16 vector<pair<int, int> >a[maxn]; 17 int ID; 18 int B, n; 19 bool e[maxn]; 20 ll dp[maxn]; 21 22 int getid(char s[]) { 23 if (!mp.count(s)) { 24 mp[s] = ++ID; 25 a[ID].clear(); 26 cc[ID] = inf; 27 vv[ID] = -inf; 28 in[ID] = 0; 29 } 30 return mp[s]; 31 } 32 33 int main() { 34 while (~scanf("%d%d", &B, &n)) { 35 mp.clear(); 36 ID = 0; 37 for (int i = 1; i <= n; i++) { 38 scanf("%s%s%s%d%d", s1[i], s2[i], s3[i], &c[i], &v[i]); 39 int z = getid(s1[i]); 40 int x = getid(s2[i]); 41 int y = getid(s3[i]); 42 ++in[z]; 43 a[x].push_back({ y,i }); 44 a[y].push_back({ x,i }); 45 e[i] = 0; 46 } 47 int top = 0; 48 for (int i = 1; i <= ID; i++) { 49 if (in[i] == 0) { 50 sta[++top] = i; 51 cc[i] = vv[i] = 0; 52 } 53 } 54 while (top) { 55 int x = sta[top--]; 56 for (auto it : a[x]) { 57 int y = it.first; 58 int o = it.second; 59 if (!e[o] && in[y] == 0) { 60 e[o] = 1; 61 int z = mp[s1[o]]; 62 int cost = cc[x] + cc[y] + c[o]; 63 int val = vv[x] + vv[y] + v[o]; 64 if (cost<cc[z] || cost == cc[z] && val>vv[z]) { 65 cc[z] = cost; 66 vv[z] = val; 67 } 68 if (--in[z] == 0) { 69 sta[++top] = z; 70 } 71 } 72 } 73 } 74 memset(dp, 0, sizeof(dp)); 75 dp[0] = 0; 76 for (int i = 1; i <= ID; ++i) { 77 for (int j = B; j >= cc[i]; --j) { 78 dp[j] = max(dp[j], dp[j - cc[i]] + vv[i]); 79 } 80 } 81 82 int cost = 0; 83 ll val = 0; 84 for (int i = 1; i <= B; i++) { 85 if (dp[i] > val) { 86 val = dp[i]; 87 cost = i; 88 } 89 } 90 printf("%lld %d ", val, cost); 91 } 92 }
F题:
根据 x * y 的和除以w即可得出 L的值
#include<bits/stdc++.h> using namespace std; #define ll long long const int maxn = 2005; int main() { int w,l; while (~scanf("%d", &w)) { int n; scanf("%d", &n); ll sum = 0; while (n--) { int x, y; scanf("%d%d", &x, &y); sum += x * y; } l = sum / w; printf("%d ", l); } return 0; }
G题:
有两种跑匹配的方法,一种是找到有可能对答案做出贡献的快递员到货物的路线建二分图,左边是快递员,右边是货物,权值设置为 len(r->b) - len(c->b),跑一遍最大权值匹配(特判二分图无边的情况,因为最少需要1个快递员运送货物)。
另外一种更简单的方法是是我们建两组点,一组是快递员和n-1个饭店,一组是货物,分别连接快递员到货物,饭店到货物的边,跑一边最大权值匹配。当然这题也可以用最小费用流来做,但需要优化添边的数目以免超时。
#pragma warning(disable:4996) #include<bits/stdc++.h> using namespace std; typedef pair<int, int> pii; typedef pair<double, int>pdi; #define ll long long #define CLR(a,b) memset(a,b,sizeof(a)) #define _for(i, a, b) for (int i = a; i < b; ++i) const int mod = (int)1e9 + 7; const int maxn = 2005; const double eps = 1e-8; const double pi = acos(-1.0); const int inf = 0x3f3f3f3f; struct node { int x, y; }; struct bc_edge { int dif, bottle, cart; bool operator<(const bc_edge & r) const { return dif < r.dif; } }; int cal_dist(node l, node r) { return abs(l.x - r.x) + abs(l.y - r.y); } node a[maxn], b[maxn]; int dis[maxn]; const int N = 2005; const int INF = 0x3f3f3f3f; int nx, ny;//两边的点数 int g[N][N];//二分图描述 int linker[N], lx[N], ly[N];//y中各点匹配状态,x,y中的点标号 int slack[N]; bool visx[N], visy[N]; bool DFS(int x) { visx[x] = true; for (int y = 0; y < ny; y++) { if (visy[y])continue; int tmp = lx[x] + ly[y] - g[x][y]; if (tmp == 0) { visy[y] = true; if (linker[y] == -1 || DFS(linker[y])) { linker[y] = x; return true; } } else if (slack[y] > tmp) slack[y] = tmp; } return false; } int KM() { memset(linker, -1, sizeof(linker)); memset(ly, 0, sizeof(ly)); for (int i = 0; i < nx; i++) { lx[i] = -INF; for (int j = 0; j < ny; j++) if (g[i][j] > lx[i]) lx[i] = g[i][j]; } for (int x = 0; x < nx; x++) { for (int i = 0; i < ny; i++) slack[i] = INF; while (true) { memset(visx, false, sizeof(visx)); memset(visy, false, sizeof(visy)); if (DFS(x))break; int d = INF; for (int i = 0; i < ny; i++) if (!visy[i] && d > slack[i]) d = slack[i]; for (int i = 0; i < nx; i++) if (visx[i]) lx[i] -= d; for (int i = 0; i < ny; i++) { if (visy[i])ly[i] += d; else slack[i] -= d; } } } int res = 0; for (int i = 0; i < ny; i++) if (linker[i] != -1) res += g[linker[i]][i]; return res; } int main() { int n, m; int ans = 0; node t; scanf("%d%d", &n, &m); _for(i, 0, n) scanf("%d%d", &a[i].x, &a[i].y); _for(i, 0, m) scanf("%d%d", &b[i].x, &b[i].y); scanf("%d%d", &t.x, &t.y); _for(i, 0, n) { dis[i] = cal_dist(t, a[i]); ans += 2 * dis[i]; } // cout << ans << endl; vector<bc_edge> v; _for(i, 0, n) { _for(j, 0, m) { int tmp = cal_dist(a[i], b[j]) - dis[i]; v.push_back({ tmp, i, j }); } } sort(begin(v), end(v)); for (int i = 0; i < (int)v.size(); ++i) { if (v[i].dif < 0) { int x = v[i].bottle; int y = v[i].cart; g[x][y] = -v[i].dif; } else break; } nx = n + m, ny = n + m; int tmp = -v[0].dif; if (v[0].dif < 0) { tmp = KM(); } printf("%d ", ans - tmp); return 0; }
H题:
I题:
J题:
#include<bits/stdc++.h> using namespace std; #define ll long long #define CLR(a,b) memset(a,b,sizeof(a)) const int mod = 1e9 + 7; const int maxn = 2005; const double eps = 1e-8; const double pi = acos(-1.0); const int inf = 0x3f3f3f3f; ll a[4], b[4], x, y; int c[4] = { 1,3,2 }; int d[4] = { 2,1,3 }; ll sum[5]; ll chang, kuan; int n, i, j, f; int main() { chang = 0; kuan = 0; scanf("%d", &n); for (i = 1; i <= n; ++i) { scanf("%lld", &x); a[i % 3] += x; } for (i = 1; i <= n; ++i) { scanf("%lld", &x); b[i % 3] += x; } printf("%lld %lld %lld ", b[1] * a[2] + a[1] * b[2] + a[0] * b[0], b[2] * a[2] + a[0] * b[1] + a[1] * b[0], b[1] * a[1] + a[0] * b[2] + a[2] * b[0]); return 0; }
K题:
求吹起最小的宽度,吹灭蛋糕上所有的蜡烛,用旋转卡壳做出凸包上每个点到另一线的距离的最小值即可
以上是关于ACM-ICPC SouthWestern Europe Regional Contest 2017题解的主要内容,如果未能解决你的问题,请参考以下文章