5/5
这一场是比较水的一场(当然我是指div2),所以前面三题就略过吧。。。
题D D. Recover the String
题意:让你构造一个01串,给你00,01,10,11的子序列个数,问你有没有满足的串。
题解:这题实际上并不难, 只是分类讨论有点麻烦。
首先是00和11一定是满足n * (n - 1) / 2,先判定一下
然后得到0的个数x,1的个数y
然后我们注意到,现一开始所有的0放在一起,然后插入一个位置k,那么我们发现01多了k,10多了x – k;假设这y个1 的位置是k1,k2,……,ky,然后01的个数和是sum{ki},然后10的和为xy -sum{ki},只要先放多个1在最右端,然后将余数放在中间某个位置即可。这个很容易想到,关键是易错点:0和1的个数为0和1的时候要特判,为了避免出错,代码写得恶心一点也无妨。。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /*zhen hao*/
2 #include <bits/stdc++.h>
3 using namespace std;
4
5 #define lson l, m, rt*2
6 #define rson m + 1, r, rt*2+1
7 #define X first
8 #define Y second
9
10 typedef pair<int,int> PII;
11 typedef long long LL;
12 typedef unsigned long long ULL;
13
14 const int N = 1e9;
15 vector<LL> v;
16
17 void init() {
18 for (int i = 1; ; i++) {
19 if (1LL * i * (i - 1) / 2 > N) break;
20 v.push_back(1LL * i * (i - 1) / 2);
21 }
22 }
23
24 int get_num(LL x) {
25 int p = lower_bound(v.begin(), v.end(), x) - v.begin();
26 if (v[p] != x) return -1;
27 else return p + 1;
28 }
29
30 char ans[1000010];
31
32 int main() {
33 // freopen("case.in", "r", stdin);
34 init();
35 LL a00, a01, a10, a11;
36 cin >> a00 >> a01 >> a10 >> a11;
37 // cout << get_num(a00) << ' ' << get_num(a11) << endl;
38 int x = get_num(a00), y = get_num(a11);
39 // cout << x << ' ' << y << endl;
40 if (x == -1 || y == -1) {
41 puts("Impossible");
42 return 0;
43 }
44 if (a00 == 0) {
45 if (a11 == 0) {
46 if (a01 == 0 && a10 == 0) puts("0");
47 else if (a01 == 1 && a10 == 0) puts("01");
48 else if (a01 == 0 && a10 == 1) puts("10");
49 else puts("Impossible");
50 }
51 else {
52 if (a01 + a10 == y) {
53 for (int i = 0; i < y - a01; i++) putchar('1');
54 putchar('0');
55 for (int i = 0; i < a01; i++) putchar('1');
56 puts("");
57 }
58 else if (a01 + a10 == 0) {
59 for (int i = 0; i < y; i++) putchar('1');
60 puts("");
61 }
62 else puts("Impossible");
63 }
64 return 0;
65 }
66 if (a11 == 0) {
67 if (a01 + a10 == x) {
68 for (int i = 0; i < x - a10; i++) putchar('0');
69 putchar('1');
70 for (int i = 0; i < a10; i++) putchar('0');
71 puts("");
72 }
73 else if (a01 + a10 == 0) {
74 for (int i = 0; i < x; i++) putchar('0');
75 puts("");
76 }
77 else puts("Impossible");
78 return 0;
79 }
80 if (1LL * x * y != a01 + a10) {
81 puts("Impossible");
82 return 0;
83 }
84 int head = a01 / y, mid = a01 % y != 0, tail = x - head - mid;
85 if (head > x || tail < 0) {
86 puts("Impossible");
87 return 0;
88 }
89 int cnt = 0;
90 for (int i = 0; i < head; i++) ans[cnt++] = '0';
91 if (mid) {
92 int num = a01 % y;
93 for (int i = 0; i < y - num; i++) ans[cnt++] = '1';
94 ans[cnt++] = '0';
95 for (int i = 0; i < num; i++) ans[cnt++] = '1';
96 }
97 else {
98 for (int i = 0; i < y; i++) ans[cnt++] = '1';
99 }
100 for (int i = 0; i < tail; i++) ans[cnt++] = '0';
101 puts(ans);
102 return 0;
103 }
题E
题意:定义“删边”,将一条边删掉分成两个子树,其中一棵子树可以任意接在另一棵子树的任意结点上,给你一棵树,对于每个点问你能不能通过至多删掉一条边使得这个点成为重心。
题解:实际上做法很简单易懂,对于一个点使得以它为根,然后找出最大的一个子树,然后问你这棵子树能不能分出一个子树的size为x,使得x <= n / 2,然后剩余的子树的size也是<=n / 2。所以我们只要对于每个点求出一个val[v]表示以他为根的子树v中最大的分出的size不超过n / 2是多少,然后对于每个子树size[v] – val[v] <= n / 2均满足即可。如果单纯地做复杂度是O(n ^ 2)。要利用dp的思想任意选一个点为根,然后dfs三次,第一次求出sz[v]表示这棵子树的size,并且转化成有根树。第二次dfs求出down[v]表示以v为根的子树中最大的不超过n / 2的子树的size是多少。第三次就是求出最up[v]表示除了v这个子树的另外一个子树的结点不超过n / 2的最大子树(这个比较麻烦,要记录最大和次大,然后传递给子树具体看代码)。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /*zhen hao*/ 2 #include <bits/stdc++.h> 3 using namespace std; 4 5 #define lson l, m, rt*2 6 #define rson m + 1, r, rt*2+1 7 #define X first 8 #define Y second 9 10 typedef pair<int,int> PII; 11 typedef long long LL; 12 typedef unsigned long long ULL; 13 14 const int N = 4e5 + 10; 15 int up[N], down[N], sz[N], fa[N]; 16 int n; 17 18 vector<int> g[N]; 19 20 void dfs_sz(int u, int p = - 1) { 21 sz[u] = 1; 22 fa[u] = p; 23 for (int i = 0; i < (int)g[u].size(); i++) { 24 int v = g[u][i]; 25 if (v == p) continue; 26 dfs_sz(v, u); 27 sz[u] += sz[v]; 28 } 29 } 30 31 void dfs_down(int u, int p = -1) { 32 if (sz[u] <= n / 2) down[u] = sz[u]; 33 for (int i = 0; i < (int)g[u].size(); i++) { 34 int v = g[u][i]; 35 if (v == p) continue; 36 dfs_down(v, u); 37 down[u] = max(down[u], down[v]); 38 } 39 } 40 41 void dfs_up(int u, int p = -1, int pre = 0) { 42 // cout << u << ' ' << p << ' ' << pre << endl; 43 up[u] = n - sz[u] <= n / 2 ? n - sz[u] : pre; 44 int _max = 0, next_max = 0; 45 for (int i = 0; i < (int)g[u].size(); i++) { 46 int v = g[u][i]; 47 if (v == p) continue; 48 if (down[v] >= _max) { 49 next_max = _max; 50 _max = down[v]; 51 } 52 else if (down[v] >= next_max) { 53 next_max = down[v]; 54 } 55 } 56 for (int i = 0; i < (int)g[u].size(); i++) { 57 int v = g[u][i]; 58 if (v == p) continue; 59 if (down[v] == _max) dfs_up(v, u, max(up[u], next_max)); 60 else dfs_up(v, u, max(up[u], _max)); 61 } 62 } 63 64 int main() { 65 // freopen("case.in", "r", stdin); 66 cin >> n; 67 for (int i = 0; i < n - 1; i++) { 68 int u, v; 69 scanf("%d%d", &u, &v); 70 u--; v--; 71 g[u].push_back(v); 72 g[v].push_back(u); 73 } 74 dfs_sz(0); 75 dfs_down(0); 76 dfs_up(0); 77 // for (int i = 0; i < n; i++) cout << sz[i] << ' ' << down[i] << ' ' << up[i] << endl; 78 for (int u = 0; u < n; u++) { 79 int ok = 1; 80 for (int i = 0; i < (int)g[u].size(); i++) { 81 int v = g[u][i]; 82 if (v == fa[u]) { 83 if (n - sz[u] - up[u] > n / 2) ok = 0; 84 } 85 else { 86 if (sz[v] - down[v] > n / 2) ok = 0; 87 } 88 } 89 printf("%d ", ok); 90 } 91 puts(""); 92 return 0; 93 }