AtCoder Grand Contest 014 题解
A - Cookie Exchanges
直接模拟即可,如果出现循环了那就GG了。
1 //waz 2 #include <bits/stdc++.h> 3 4 using namespace std; 5 6 #define mp make_pair 7 #define pb push_back 8 #define fi first 9 #define se second 10 #define ALL(x) (x).begin(), (x).end() 11 #define SZ(x) ((int)((x).size())) 12 13 typedef pair<int, int> PII; 14 typedef vector<int> VI; 15 typedef long long int64; 16 typedef unsigned int uint; 17 typedef unsigned long long uint64; 18 19 #define gi(x) ((x) = F()) 20 #define gii(x, y) (gi(x), gi(y)) 21 #define giii(x, y, z) (gii(x, y), gi(z)) 22 23 int F() 24 { 25 char ch; 26 int x, a; 27 while (ch = getchar(), (ch < '0' || ch > '9') && ch != '-'); 28 if (ch == '-') ch = getchar(), a = -1; 29 else a = 1; 30 x = ch - '0'; 31 while (ch = getchar(), ch >= '0' && ch <= '9') 32 x = (x << 1) + (x << 3) + ch - '0'; 33 return a * x; 34 } 35 36 int A, B, C; 37 38 map<pair<PII,int>, bool> h; 39 40 int cnt = 0; 41 42 int main() 43 { 44 giii(A, B, C); 45 while (1) 46 { 47 if ((A & 1) || (B & 1) || (C & 1)) 48 { 49 printf("%d\n", cnt); 50 return 0; 51 } 52 if (h.count(mp(mp(A, B), C))) 53 { 54 puts("-1"); 55 return 0; 56 } 57 ++cnt; 58 int a = A, b = B, c = C; 59 h[mp(mp(A, B), C)] = 1; 60 A = (b + c) >> 1; 61 B = (a + c) >> 1; 62 C = (a + b) >> 1; 63 } 64 }
B - Unplanned Queries
我们发现本质就是异或,判断能不能边全为0,我们发现异或操作lca是不会变的,那么我们只要算出每个点出现次数是不是偶数就好了。
1 //waz 2 #include <bits/stdc++.h> 3 4 using namespace std; 5 6 #define mp make_pair 7 #define pb push_back 8 #define fi first 9 #define se second 10 #define ALL(x) (x).begin(), (x).end() 11 #define SZ(x) ((int)((x).size())) 12 13 typedef pair<int, int> PII; 14 typedef vector<int> VI; 15 typedef long long int64; 16 typedef unsigned int uint; 17 typedef unsigned long long uint64; 18 19 #define gi(x) ((x) = F()) 20 #define gii(x, y) (gi(x), gi(y)) 21 #define giii(x, y, z) (gii(x, y), gi(z)) 22 23 int F() 24 { 25 char ch; 26 int x, a; 27 while (ch = getchar(), (ch < '0' || ch > '9') && ch != '-'); 28 if (ch == '-') ch = getchar(), a = -1; 29 else a = 1; 30 x = ch - '0'; 31 while (ch = getchar(), ch >= '0' && ch <= '9') 32 x = (x << 1) + (x << 3) + ch - '0'; 33 return a * x; 34 } 35 36 int w[100010]; 37 38 int n, m; 39 40 int main() 41 { 42 gii(n, m); 43 for (int i = 1; i <= m; ++i) 44 { 45 int u, v; 46 gii(u, v); 47 w[u] ^= 1; 48 w[v] ^= 1; 49 } 50 for (int i = 1; i <= n; ++i) 51 { 52 if (w[i]) 53 { 54 puts("NO"); 55 return 0; 56 } 57 } 58 puts("YES"); 59 return 0; 60 }
C - Closed Rooms
走完一次之后,后面肯定可以直接开锁不用绕圈子。算出k步之内能走到哪,直接和到边界距离加起来就好了。
1 //waz 2 #include <bits/stdc++.h> 3 4 using namespace std; 5 6 #define mp make_pair 7 #define pb push_back 8 #define fi first 9 #define se second 10 #define ALL(x) (x).begin(), (x).end() 11 #define SZ(x) ((int)((x).size())) 12 13 typedef pair<int, int> PII; 14 typedef vector<int> VI; 15 typedef long long int64; 16 typedef unsigned int uint; 17 typedef unsigned long long uint64; 18 19 #define gi(x) ((x) = F()) 20 #define gii(x, y) (gi(x), gi(y)) 21 #define giii(x, y, z) (gii(x, y), gi(z)) 22 23 int F() 24 { 25 char ch; 26 int x, a; 27 while (ch = getchar(), (ch < '0' || ch > '9') && ch != '-'); 28 if (ch == '-') ch = getchar(), a = -1; 29 else a = 1; 30 x = ch - '0'; 31 while (ch = getchar(), ch >= '0' && ch <= '9') 32 x = (x << 1) + (x << 3) + ch - '0'; 33 return a * x; 34 } 35 36 int h, w, k; 37 38 char str[810][810]; 39 40 int d[810][810]; 41 42 PII operator + (const PII &a, const PII &b) { return mp(a.fi + b.fi, a.se + b.se); } 43 44 bool check(const PII &a) { return a.fi >= 1 && a.fi <= h && a.se >= 1 && a.se <= w && str[a.fi][a.se] != '#'; } 45 46 int main() 47 { 48 memset(d, 63, sizeof d); 49 giii(h, w, k); 50 for (int i = 1; i <= h; ++i) scanf("%s", str[i] + 1); 51 int l = 0, r = 0; 52 static PII q[810 * 810]; 53 for (int i = 1; i <= h; ++i) 54 for (int j = 1; j <= w; ++j) 55 if (str[i][j] == 'S') 56 q[r++] = mp(i, j), d[i][j] = 0; 57 while (l < r) 58 { 59 PII u = q[l++]; 60 if (check(u + mp(1, 0))) 61 { 62 PII v = u + mp(1, 0); 63 if (d[v.fi][v.se] > d[u.fi][u.se] + 1) 64 { 65 d[v.fi][v.se] = d[u.fi][u.se] + 1; 66 q[r++] = v; 67 } 68 } 69 if (check(u + mp(-1, 0))) 70 { 71 PII v = u + mp(-1, 0); 72 if (d[v.fi][v.se] > d[u.fi][u.se] + 1) 73 { 74 d[v.fi][v.se] = d[u.fi][u.se] + 1; 75 q[r++] = v; 76 } 77 } 78 if (check(u + mp(0, 1))) 79 { 80 PII v = u + mp(0, 1); 81 if (d[v.fi][v.se] > d[u.fi][u.se] + 1) 82 { 83 d[v.fi][v.se] = d[u.fi][u.se] + 1; 84 q[r++] = v; 85 } 86 } 87 if (check(u + mp(0, -1))) 88 { 89 PII v = u + mp(0, -1); 90 if (d[v.fi][v.se] > d[u.fi][u.se] + 1) 91 { 92 d[v.fi][v.se] = d[u.fi][u.se] + 1; 93 q[r++] = v; 94 } 95 } 96 } 97 int ans = d[0][0]; 98 for (int i = 1; i <= h; ++i) 99 { 100 for (int j = 1; j <= w; ++j) 101 { 102 int v = min(min(i - 1, h - i), min(j - 1, w - j)); 103 if (!v && d[i][j] <= k) ans = 1; 104 if (d[i][j] <= k) ans = min(ans, 1 + (v - 1) / k + 1); 105 } 106 } 107 printf("%d\n", ans); 108 return 0; 109 }
D - Black and White Tree
如果树是奇数个点的,肯定先手胜。
我们来证明这个结论,可以用归纳。
首先n=1时成立。
接着我们可以找到一个点,使得树分成两个及以上奇数的部分,如果后手染其中一棵,你就往另一棵递归。
那么很显然,偶数的时候只要能找到这么一个点也能胜利。
1 //waz 2 #include <bits/stdc++.h> 3 4 using namespace std; 5 6 #define mp make_pair 7 #define pb push_back 8 #define fi first 9 #define se second 10 #define ALL(x) (x).begin(), (x).end() 11 #define SZ(x) ((int)((x).size())) 12 13 typedef pair<int, int> PII; 14 typedef vector<int> VI; 15 typedef long long int64; 16 typedef unsigned int uint; 17 typedef unsigned long long uint64; 18 19 #define gi(x) ((x) = F()) 20 #define gii(x, y) (gi(x), gi(y)) 21 #define giii(x, y, z) (gii(x, y), gi(z)) 22 23 int F() 24 { 25 char ch; 26 int x, a; 27 while (ch = getchar(), (ch < '0' || ch > '9') && ch != '-'); 28 if (ch == '-') ch = getchar(), a = -1; 29 else a = 1; 30 x = ch - '0'; 31 while (ch = getchar(), ch >= '0' && ch <= '9') 32 x = (x << 1) + (x << 3) + ch - '0'; 33 return a * x; 34 } 35 36 const int N = 1e5 + 10; 37 38 int n; 39 40 int siz[N]; 41 42 VI edge[N]; 43 44 bool ok; 45 46 void dfs(int u, int fa) 47 { 48 siz[u] = 1; 49 int cnt = 0; 50 for (auto v : edge[u]) 51 { 52 if (v == fa) continue; 53 dfs(v, u); 54 siz[u] += siz[v]; 55 cnt += (siz[v] & 1); 56 } 57 cnt += ((n - siz[u]) & 1); 58 if (cnt > 1) ok = 1; 59 } 60 61 int main() 62 { 63 gi(n); 64 for (int i = 1; i < n; ++i) 65 { 66 int u, v; 67 gii(u, v); 68 edge[u].pb(v); 69 edge[v].pb(u); 70 } 71 dfs(1, 0); 72 if (n & 1) ok = 1; 73 puts(ok ? "First" : "Second"); 74 return 0; 75 }
E - Blue and Red Tree
最后删的边肯定两棵树都出现过,我们就倒着模拟,合并的时候用启发式合并就好了。
1 //waz 2 #include <bits/stdc++.h> 3 4 using namespace std; 5 6 #define mp make_pair 7 #define pb push_back 8 #define fi first 9 #define se second 10 #define ALL(x) (x).begin(), (x).end() 11 #define SZ(x) ((int)((x).size())) 12 13 typedef pair<int, int> PII; 14 typedef vector<int> VI; 15 typedef long long int64; 16 typedef unsigned int uint; 17 typedef unsigned long long uint64; 18 19 #define gi(x) ((x) = F()) 20 #define gii(x, y) (gi(x), gi(y)) 21 #define giii(x, y, z) (gii(x, y), gi(z)) 22 23 int F() 24 { 25 char ch; 26 int x, a; 27 while (ch = getchar(), (ch < '0' || ch > '9') && ch != '-'); 28 if (ch == '-') ch = getchar(), a = -1; 29 else a = 1; 30 x = ch - '0'; 31 while (ch = getchar(), ch >= '0' && ch <= '9') 32 x = (x << 1) + (x << 3) + ch - '0'; 33 return a * x; 34 } 35 36 const int N = 1e5 + 10; 37 38 map<int, int> h[N]; 39 40 set<int> edge[N]; 41 42 queue<PII> q; 43 44 void link(int u, int v) 45 { 46 edge[u].insert(v); 47 edge[v].insert(u); 48 if (u > v) swap(u, v); 49 ++h[u][v]; 50 if (h[u][v] == 2) 51 { 52 q.push(mp(u,v)); 53 } 54 if (h[u][v] > 2) 55 { 56 puts("NO"); 57 exit(0); 58 } 59 } 60 61 void cut(int u, int v) 62 { 63 edge[u].erase(v); 64 if (u > v) swap(u, v); 65 h[u].erase(v); 66 } 67 68 int fa[N], n; 69 70 int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); } 71 72 int main() 73 { 74 gi(n); 75 for (int i = 1; i <= n; ++i) fa[i] = i; 76 for (int i = 1; i < n; ++i) 77 { 78 int u, v; 79 gii(u, v); 80 link(u, v); 81 } 82 for (int i = 1; i < n; ++i) 83 { 84 int u, v; 85 gii(u, v); 86 link(u, v); 87 } 88 for (int i = 1; i < n; ++i) 89 { 90 int u, v; 91 do 92 { 93 if (q.empty()) 94 { 95 puts("NO"); 96 return 0; 97 } 98 u = q.front().fi; 99 v = q.front().se; 100 u = find(u); 101 v = find(v); 102 q.pop(); 103 } while (u == v); 104 if (SZ(edge[u]) > SZ(edge[v])) swap(u, v); 105 fa[u] = v; 106 cut(v, u); 107 for (auto x : edge[u]) 108 { 109 x = find(x); 110 if (x == v) continue; 111 link(x, v); 112 cut(x, u); 113 } 114 edge[u].clear(); 115 } 116 puts("YES"); 117 return 0; 118 }
F - Strange Sorting
找规律+递推。。。
1 //waz 2 #include <bits/stdc++.h> 3 4 using namespace std; 5 6 #define mp make_pair 7 #define pb push_back 8 #define fi first 9 #define se second 10 #define ALL(x) (x).begin(), (x).end() 11 #define SZ(x) ((int)((x).size())) 12 13 typedef pair<int, int> PII; 14 typedef vector<int> VI; 15 typedef long long int64; 16 typedef unsigned int uint; 17 typedef unsigned long long uint64; 18 19 #define gi(x) ((x) = F()) 20 #define gii(x, y) (gi(x), gi(y)) 21 #define giii(x, y, z) (gii(x, y), gi(z)) 22 23 int F() 24 { 25 char ch; 26 int x, a; 27 while (ch = getchar(), (ch < '0' || ch > '9') && ch != '-'); 28 if (ch == '-') ch = getchar(), a = -1; 29 else a = 1; 30 x = ch - '0'; 31 while (ch = getchar(), ch >= '0' && ch <= '9') 32 x = (x << 1) + (x << 3) + ch - '0'; 33 return a * x; 34 } 35 36 const int N = 2e5 + 10; 37 38 int n, p[N], f[N], t[N]; 39 40 bool ck(int a, int b, int c) 41 { 42 return (a < b && b < c) || (b < c && c < a) || (c < a && a < b); 43 } 44 45 int main() 46 { 47 gi(n); 48 for (int i = 1; i <= n; ++i) p[F()] = i; 49 for (int i = n - 1; i; --i) 50 { 51 if (!t[i + 1]) 52 { 53 if (p[i] > p[i + 1]) t[i] = 1, f[i] = i + 1; 54 } 55 else 56 { 57 if (ck(p[f[i + 1]], p[i], p[i + 1])) t[i] = t[i + 1], f[i] = f[i + 1]; 58 else t[i] = t[i + 1] + 1, f[i] = i + 1; 59 } 60 } 61 printf("%d\n", t[1]); 62 return 0; 63 }