Codeforces Round 500 (Div 2) Solution
从这里开始
Problem A Piles With Stones
题目大意
有若干堆石子排成一排。第一天科研人员记录了它们每一堆的数量。第二天科研人员又记录了这些石子的数量。晚上可能有非常多的游客来过。每个游客有三种可选操作:
- 不对石子做什么。
- 拿走一个石子
- 将一个石子移动到另一堆中。
给定两天记录的数据问是否可能。
直接判断第二天的数量是否小于等于第一天。
Code
1 /** 2 * Codeforces 3 * Problem#1013A 4 * Accepted 5 * Time: 31ms 6 * Memory: 0k 7 */ 8 #include <iostream> 9 #include <cstdlib> 10 #include <cstdio> 11 using namespace std; 12 typedef bool boolean; 13 14 int n; 15 int s1 = 0; 16 17 inline void init() { 18 scanf("%d", &n); 19 for (int i = 1, x; i <= n; i++) 20 scanf("%d", &x), s1 += x; 21 for (int i = 1, x; i <= n; i++) 22 scanf("%d", &x), s1 -= x; 23 if (s1 < 0) 24 puts("No"); 25 else 26 puts("Yes"); 27 } 28 29 int main() { 30 init(); 31 return 0; 32 }
Problem B And
题目大意
给定$n$个数和$x$,将一个数按位与$x$算作一次操作,要求序列中至少有两个相同的数,问最少的操作数。无解输出-1.
显然答案只可能是-1,0,1,2。
第一种是无解。第二种不需要操作。第三种是一个数按位与x后与另一个数相同。最后一种是两个数与x后相同。
每个数与x,然后用stl判一判。
Code
1 /** 2 * Codeforces 3 * Problem#1013B 4 * Accepted 5 * Time: 124ms 6 * Memory: 4200k 7 */ 8 #include <bits/stdc++.h> 9 using namespace std; 10 typedef bool boolean; 11 12 const int N = 1e5 + 5; 13 14 int n, x; 15 int ar[N]; 16 map<int, int> sa; 17 set<int> sb; 18 19 inline void init() { 20 scanf("%d%d", &n, &x); 21 for (int i = 1, a; i <= n; i++) { 22 scanf("%d", &a); 23 ar[i] = a; 24 if (sa.count(a)) { 25 puts("0"); 26 exit(0); 27 } 28 sa[a] = i; 29 } 30 } 31 32 int res = 3; 33 inline void solve() { 34 for (int i = 1; i <= n; i++) { 35 int b = ar[i] & x; 36 if (sb.count(b)) 37 res = min(res, 2); 38 sb.insert(b); 39 if (sa.count(b) && sa[b] != i) 40 res = 1; 41 } 42 if (res == 3) 43 puts("-1"); 44 else 45 printf("%d", res); 46 } 47 48 int main() { 49 init(); 50 solve(); 51 return 0; 52 }
Problem C Photo of The Sky
题目大意
有$2n$个数,要求分成元素个数相等的两组$X$和$Y$,且$\left(max(X) - min(X)\right)\left(max(Y) - min(Y)\right)$最小。问这个最小值。其中$min(X),max(X)$分别表示$X$中最小、最大的数。
考虑两种情况:
- 如果最大值和最小值在同一个集合内,那么设下的数一定是排序后连续的一段,否则我取这中间最小的和排它后面的$(n - 1)$可以更优。这一部分可以$O(n)$处理掉。
- 如果最大值和最小值在不同集合内,那么我们要使最小值在的集合的最大值尽量小,最大值在的集合的最小值尽量大。显然取前$n$小作为$X$,剩下的作为$Y$最优。
Code
1 /** 2 * Codeforces 3 * Problem#1013C 4 * Accepted 5 * Time: 93ms 6 * Memory: 800k 7 */ 8 #include <bits/stdc++.h> 9 using namespace std; 10 typedef bool boolean; 11 12 const int N = 2e5 + 5; 13 14 int n; 15 int ar[N]; 16 17 inline void init() { 18 scanf("%d", &n); 19 n <<= 1; 20 for (int i = 1; i <= n; i++) 21 scanf("%d", ar + i); 22 } 23 24 inline void solve() { 25 sort(ar + 1, ar + n + 1); 26 n >>= 1; 27 long long res = (ar[n] - ar[1]) * 1ll * (ar[n << 1] - ar[n + 1]); 28 for (int i = 2; i <= n; i++) 29 res = min((ar[i + n - 1] - ar[i]) * 1ll * (ar[n << 1] - ar[1]), res); 30 cout << res << endl; 31 } 32 33 int main() { 34 init(); 35 solve(); 36 return 0; 37 }
Problem D Chemical table
题目大意
有一个$n\times m$的网格图,如果三个有原料的格子恰好在恰好围住它们的最小矩形的三个"顶点"上,那么剩下的一个"顶点"能自动填上原料。现在有$q$个位置填上了原料。你可以在某个格子上放置原料,问如果要整张图都填满原料,至少还要放置多少原料。
一个比较经典的模型?
每行每列分别建一个点,$(i, j)$ 有原料那么第 $i$ 行向第 $j$ 列连一条边。
然后算算连通块数就能算答案了。
Code
1 /** 2 * Codeforces 3 * Problem#1013D 4 * Accepted 5 * Time: 109ms 6 * Memory: 6500k 7 */ 8 #include <bits/stdc++.h> 9 using namespace std; 10 typedef bool boolean; 11 12 const int N = 2e5 + 5; 13 14 int n, m, q; 15 boolean v1[N], v2[N]; 16 int uf[N << 1]; 17 18 int find(int x) { 19 return (uf[x] == x) ? (x) : (uf[x] = find(uf[x])); 20 } 21 22 inline void init() { 23 scanf("%d%d%d", &n, &m, &q); 24 for (int i = 1; i <= n + m; i++) 25 uf[i] = i; 26 for (int i = 1, x, y; i <= q; i++) { 27 scanf("%d%d", &x, &y); 28 uf[find(x)] = find(y + n); 29 } 30 } 31 32 int res = -1; 33 inline void solve() { 34 for (int i = 1; i <= n + m; i++) 35 if (find(i) == i) 36 res++; 37 printf("%d\n", res); 38 } 39 40 int main() { 41 init(); 42 solve(); 43 return 0; 44 }
Problem E Hills
题目大意
有一条连绵起伏的山脉,第$i$个山峰的高度是$h_{i}$。有一个工程队,每小时能将任意一座山的高度减少1。一个山峰能建立房子当且仅当它两边的山峰高度严格小于它。要求输出当建立$1. \cdots, \left \lceil \frac{n}{2} \right \rceil$个房子的时候至少需要工程队施工的时间。
显然用$f[i][j][0 / 1]$表示考虑到第$i$座山峰,已经建立了$j$个房子,当期山峰是否建立房子的最少施工时间。
首先如果一个地方要建立房子,那么会贪心地使周围两座山的高度尽量高(因为这样花的时间少),因此如果知道一座山两边有没有盖房子,这座山在最优的情况下的高度是确定的。
转移也比较显然。如果当前山峰没有建立房子,那么从$i - 1$转移。
如果当前山峰建立了房子,那么前一座山一定不能建房子。考虑$i - 2$座山上有没有建房子,如果建立了,那么补上第$i - 1$座山的高度差,以及减少第$i + 1$座山的高度的耗时。如果没有建房子,直接计算耗时转移。
Code
1 /** 2 * Codeforces 3 * Problem#1013E 4 * Accepted 5 * Time: 124ms 6 * Memory: 98100k 7 */ 8 #include <bits/stdc++.h> 9 #ifndef WIN32 10 #define Auto "%lld" 11 #else 12 #define Auto "%I64d" 13 #endif 14 using namespace std; 15 typedef bool boolean; 16 17 #define ll long long 18 19 const int N = 5e3 + 5; 20 21 int n, hn; 22 int ar[N]; 23 int f[N][N >> 1][2]; 24 25 inline void init() { 26 scanf("%d", &n); 27 hn = (n + 1) >> 1; 28 for (int i = 1; i <= n; i++) 29 scanf("%d", ar + i); 30 } 31 32 int calc(int p) { 33 if (p < 1) return 0; 34 return ((ar[p - 1] < ar[p]) ? (0) : (ar[p - 1] - ar[p] + 1)) + ((ar[p + 1] < ar[p]) ? (0) : (ar[p + 1] - ar[p] + 1)); 35 } 36 37 int calc2(int a) { 38 if (a < 1) return calc(a + 2); 39 int res = ((ar[a - 1] < ar[a]) ? (0) : (ar[a - 1] - ar[a] + 1)); 40 res += (ar[a + 1] < min(ar[a], ar[a + 2])) ? (0) : (ar[a + 1] - min(ar[a], ar[a + 2]) + 1); 41 res += (ar[a + 3] < ar[a + 2]) ? (0) :(ar[a + 3] - ar[a + 2] + 1); 42 return res; 43 } 44 45 int res[N]; 46 47 inline void solve() { 48 memset(f, 0x7f, sizeof(f)); 49 ar[0] = -1e5 + 1, ar[n + 1] = -1e5; 50 for (int i = 0; i <= n; i++) 51 f[i][0][0] = 0; 52 f[1][1][1] = calc(1), f[1][0][0] = 0; 53 for (int i = 2; i <= n; i++) 54 for (int j = 0; j <= hn && j <= ((i + 1) >> 1); j++) { 55 if (!j) 56 f[i][j][0] = f[i - 1][j][0]; 57 else { 58 f[i][j][0] = min(f[i - 1][j][0], f[i - 1][j][1]); 59 f[i][j][1] = min(f[i - 2][j - 1][0] + calc(i), f[i - 2][j - 1][1] - calc(i - 2) + calc2(i - 2)); 60 // cerr << i << " " << calc(i) << " " << calc2(i - 2) << " " << calc(i - 2) << " " << f[i - 2][j][0] << endl; 61 } 62 } 63 64 memset(res, 0x7f, sizeof(res)); 65 for (int i = 1; i <= n; i++) 66 for (int j = 1; j <= hn; j++) 67 res[j] = min(res[j], f[i][j][0]), res[j] = min(res[j], f[i][j][1]); 68 for (int i = 1; i <= hn; i++) 69 printf("%d ", res[i]); 70 } 71 72 int main() { 73 init(); 74 solve(); 75 return 0; 76 }
Problem F AB-Strings
题目大意
有两个只含字符'a'、'b'的字符串。一次操作是指交换这两个字符串的可空前缀。问使得每个串内只包含一种字符最少的操作数。要求输出方案。保证至少有一个'a'和'b'。
显然把已经连续的相同字符断开不优,因此把连续的相同缩在一起。
然后有用的状态就只有两个串的串长,以及开头的字符是否相同。
因此我们可以暴力动态规划。
但是感觉这玩意决策不会太多,因为每次至多只会消掉两个字符。
于是我们可以对小数据进行动态规划,并打表。
然后发现第一列、第二列、第一行、第二行除去前几项决策4个一循环。
剩下的决策与它们的长度差模4的余数有关。
然后再写个链表模拟一下。交上去就过了。
如果哪位佬会证明,麻烦在评论区内写一写。
Code
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef bool boolean; 4 5 const int N = 60; 6 boolean vis[N][N][2]; 7 int f[N][N][2], p1[N][N][2], p2[N][N][2]; 8 int s1[N], s2[N]; 9 10 void update(int &f, int& p1, int& p2, int val, int sl, int sr) { 11 if (val < f || (val == f && (sl + sr < p1 + p2)) || (sl + sr == p1 + p2 && sl < p1)) 12 f = val, p1 = sl, p2 = sr; 13 } 14 15 int dp(int l, int r, int dif) { 16 if (!l || !r) 17 return 0x7f7f7f7f; 18 if (l == 1 && r == 1) 19 return (dif == 1) ? (0) : (0x7f7f7f7f); 20 if (vis[l][r][dif]) 21 return f[l][r][dif]; 22 vis[l][r][dif] = true; 23 for (int sl = 0; sl <= l; sl++) 24 for (int sr = 0; sr <= r; sr++) { 25 if (!sl && !sr) 26 continue; 27 for (int i = 0; i < sr; i++) 28 s1[i] = (dif + i) & 1; 29 s1[sr] = sl & 1; 30 for (int i = 0; i < sl; i++) 31 s2[i] = i & 1; 32 s2[sl] = (dif + sr) & 1; 33 int red1 = 0, red2 = 0; 34 for (int i = 1; i <= sr && i < l - sl + sr; i++) 35 red1 += (s1[i] == s1[i - 1]); 36 for (int i = 1; i <= sl && i < r + sl - sr; i++) 37 red2 += (s2[i] == s2[i - 1]); 38 if (!red1 && !red2) 39 continue; 40 // cerr << l << " " << r << " " << dif << " " << sl << " " << sr << " -> " << l + sr - sl - red1 << " " << r + sl - sr - red2 << " " << (s1[0] != s2[0]) << endl; 41 update(f[l][r][dif], p1[l][r][dif], p2[l][r][dif], dp(l + sr - sl - red1, r + sl - sr - red2, s1[0] != s2[0]) + 1, sl, sr); 42 } 43 return f[l][r][dif]; 44 } 45 46 int n, m, d; 47 int main() { 48 // cin >> n >> m >> d; 49 cin >> d; 50 memset(vis, false, sizeof(vis)); 51 memset(f, 0x7f, sizeof(f)); 52 // cout << dp(n, m, d) << endl; 53 freopen("list.txt", "w", stdout); 54 for (int i = 1; i <= 25; i++, cout << endl) 55 for (int j = 1; j <= 15; j++) { 56 dp(i, j, d); 57 cout << "(" << p1[i][j][d] << ", " << p2[i][j][d] << ") "; 58 // assert(p1[i][j][d] == p1[min(i, 10)][min(j, 10)][d]); 59 // assert(p2[i][j][d] == p2[min(i, 10)][min(j, 10)][d]); 60 } 61 return 0; 62 }
1 /** 2 * Codeforces 3 * Problem#1013F 4 * Accepted 5 * Time: 109ms 6 * Memory: 8000k 7 */ 8 #include <bits/stdc++.h> 9 using namespace std; 10 typedef bool boolean; 11 12 const int N = 44; 13 boolean vis[N][N][2]; 14 int f[N][N][2], p1[N][N][2], p2[N][N][2]; 15 int s1[N], s2[N]; 16 17 void update(int &f, int& p1, int& p2, int val, int sl, int sr) { 18 if (val < f || (val == f && (sl + sr < p1 + p2))) 19 f = val, p1 = sl, p2 = sr; 20 } 21 22 int dp(int l, int r, int dif) { 23 if (!l || !r) 24 return 0x7f7f7f7f; 25 if (l == 1 && r == 1) 26 return (dif == 1) ? (0) : (0x7f7f7f7f); 27 if (vis[l][r][dif]) 28 return f[l][r][dif]; 29 vis[l][r][dif] = true; 30 for (int sl = 0; sl <= l; sl++) 31 for (int sr = 0; sr <= r; sr++) { 32 if (!sl && !sr) 33 continue; 34 for (int i = 0; i < sr; i++) 35 s1[i] = (dif + i) & 1; 36 s1[sr] = sl & 1; 37 for (int i = 0; i < sl; i++) 38 s2[i] = i & 1; 39 s2[sl] = (dif + sr) & 1; 40 int red1 = 0, red2 = 0; 41 for (int i = 1; i <= sr && i < l - sl + sr; i++) 42 red1 += (s1[i] == s1[i - 1]); 43 for (int i = 1; i <= sl && i < r + sl - sr; i++) 44 red2 += (s2[i] == s2[i - 1]); 45 if (!red1 && !red2) 46 continue; 47 // cerr << l << " " << r << " " << dif << " " << sl << " " << sr << " -> " << l + sr - sl - red1 << " " << r + sl - sr - red2 << " " << (s1[0] != s2[0]) << endl; 48 update(f[l][r][dif], p1[l][r][dif], p2[l][r][dif], dp(l + sr - sl - red1, r + sl - sr - red2, s1[0] != s2[0]) + 1, sl, sr); 49 } 50 return f[l][r][dif]; 51 } 52 53 typedef class Node { 54 public: 55 Node* suf; 56 int col, s; 57 58 Node() { } 59 Node(Node* suf, int col, int s):suf(suf), col(col), s(s) { } 60 }Node; 61 62 int d; 63 int l = 1, r = 1; 64 Node *stl, *str; 65 Node nl[200005], nr[200005]; 66 char buf[200005]; 67 68 inline void init() { 69 int c1, c2; 70 scanf("%s", buf); 71 c1 = buf[0]; 72 nl[0] = Node(nl + 1, -1, -233333); 73 nl[1] = Node(nl + 2, c1, 1); 74 for (int i = 1; buf[i]; i++) 75 if (buf[i] == buf[i - 1]) 76 nl[l].s++; 77 else 78 l += 1, nl[l] = Node(nl + l + 1, buf[i], 1); 79 nl[l + 1].s = -1; 80 scanf("%s", buf); 81 c2 = buf[0]; 82 nr[0] = Node(nr + 1, -1, -233333); 83 nr[1] = Node(nr + 2, c2, 1); 84 for (int i = 1; buf[i]; i++) 85 if (buf[i] == buf[i - 1]) 86 nr[r].s++; 87 else 88 r += 1, nr[r] = Node(nr + r + 1, buf[i], 1); 89 nr[r + 1].s = -1; 90 d = (c1 != c2); 91 stl = nl, str = nr; 92 } 93 94 pair<int, int> swapS(int sl, int sr, int& l, int& r) { 95 Node *pl = stl, *psl, *pr = str, *psr; 96 int rl = 0, rr = 0; 97 for (int i = 0; i < sl; i++) 98 pl = pl->suf, rl += pl->s; 99 for (int i = 0; i < sr; i++) 100 pr = pr->suf, rr += pr->s; 101 psl = pl->suf, psr = pr->suf; 102 swap(stl, str); 103 pl->suf = psr; 104 pr->suf = psl; 105 if (pl->s > 0 && psr->s > 0 && pl->col == psr->col) { 106 pl->s += psr->s; 107 pl->suf = psr->suf; 108 r--; 109 } 110 if (pr->s > 0 && psl->s > 0 && pr->col == psl->col) { 111 pr->s += psl->s; 112 pr->suf = psl->suf; 113 l--; 114 } 115 return pair<int, int> (rl, rr); 116 } 117 118 pair<int, int> st1[4] = {pair<int, int>(1, 0), pair<int, int>(2, 1), pair<int, int>(3, 0), pair<int, int>(1, 0)}; 119 pair<int, int> st2[4] = {pair<int, int>(1, 0), pair<int, int>(2, 1), pair<int, int>(0, 1), pair<int, int>(1, 0)}; 120 pair<int, int> st3[4] = {pair<int, int>(0, 1), pair<int, int>(0, 3), pair<int, int>(0, 3), pair<int, int>(0, 1)}; 121 pair<int, int> st4[4] = {pair<int, int>(1, 1), pair<int, int>(2, 0), pair<int, int>(3, 1), pair<int, int>(1, 1)}; 122 pair<int, int> st5[4] = {pair<int, int>(1, 1), pair<int, int>(3, 1), pair<int, int>(3, 1), pair<int, int>(1, 1)}; 123 pair<int, int> st6[4] = {pair<int, int>(0, 2), pair<int, int>(1, 3), pair<int, int>(1, 3), pair<int, int>(1, 1)}; 124 125 pair<int, int> g(int x, int y, int d) { 126 if (x <= 10 && y <= 10) { 127 dp(x, y, d); 128 return pair<int, int>(p1[x][y][d], p2[x][y][d]); 129 } 130 if (!d) { 131 if (y == 1) 132 return st1[x % 4]; 133 if (y == 2) 134 return st2[x % 4]; 135 if (x == 1) 136 return st3[y % 4]; 137 if (x == 2) 138 return (y % 4 == 1) ? (pair<int, int>(1, 2)) : (pair<int, int>(0, 1)); 139 return ((((x - y) % 4 + 4) % 4) == 1) ? (pair<int, int>(1, 0)) : (pair<int, int>(0, 1)); 140 } else { 141 if (y == 1) 142 return st4[x % 4]; 143 if (y == 2) 144 return st5[x % 4]; 145 if (x == 1) 146 return (y % 4 == 2) ? (pair<int, int>(1, 3)) : (pair<int, int>(0, 2)); 147 if (x == 2) 148 return st6[y % 4]; 149 return ((((x - y) % 4 + 4) % 4) == 2) ? (pair<int, int>(0, 2)) : (pair<int, int>(1, 1)); 150 } 151 } 152 153 vector< pair<int, int> > opt; 154 inline void solve() { 155 memset(vis, false, sizeof(vis)); 156 memset(f, 0x7f, sizeof(f)); 157 while (l > 1 || r > 1) { 158 pair<int, int> s = g(l, r, d); 159 int sl = s.first, sr = s.second; 160 l = l - sl + sr, r = r + sl - sr; 161 opt.push_back(swapS(sl, sr, l, r)); 162 d = (stl->suf->col != str->suf->col); 163 } 164 printf("%d\n", (signed) opt.size()); 165 for (int i = 0; i < (signed) opt.size(); i++) 166 printf("%d %d\n", opt[i].first, opt[i].second); 167 } 168 169 int main() { 170 init(); 171 solve(); 172 return 0; 173 }