ACM-ICPC SouthWestern Europe Regional Contest 2017題解
阿新 • • 發佈:2018-08-20
clu 答案 _for 條件 拓撲 order double ide max
題目地址
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(View Code"%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\n", 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\n%d\n", val, cost); 91 } 92 }View Code
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\n", l); } return 0; }View Code
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\n", ans - tmp); return 0; }View Code
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\n", 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; }View Code
K題:
求吹起最小的寬度,吹滅蛋糕上所有的蠟燭,用旋轉卡殼做出凸包上每個點到另一線的距離的最小值即可
ACM-ICPC SouthWestern Europe Regional Contest 2017題解