AIM Tech Round 3 (Div. 2)

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的时候要特判,为了避免出错,代码写得恶心一点也无妨。。

  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的最大子树(这个比较麻烦,要记录最大和次大,然后传递给子树具体看代码)。

 

 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 }
代码君
原文地址:https://www.cnblogs.com/zhenhao1/p/5831701.html