首页 > 代码库 > 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)