首页 > 代码库 > AIM Tech Round 3 (Div. 2)

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 }
代码君

 

AIM Tech Round 3 (Div. 2)