Codeforces Round 500 (Div 2) Solution

Problem A Piles With Stones

题目大意

  有若干堆石子排成一排。第一天科研人员记录了它们每一堆的数量。第二天科研人员又记录了这些石子的数量。晚上可能有非常多的游客来过。每个游客有三种可选操作:

  1. 不对石子做什么。
  2. 拿走一个石子
  3. 将一个石子移动到另一堆中。

  给定两天记录的数据问是否可能。

   直接判断第二天的数量是否小于等于第一天。

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 A

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 B

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 C

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 D

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 E

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 }
Table Maker
  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 }
Problem F
posted @ 2018-08-02 21:24 阿波罗2003 阅读(...) 评论(...) 编辑 收藏