• 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 }
    代码君
  • 相关阅读:
    学习redis-安装和基本一些命令
    Eclipse启动报错Java was started but returned exit code=13
    踩过的坑系列之InputStream.read(byte[])方法
    <<深入Java虚拟机>>-虚拟机类加载机制-学习笔记
    <<深入Java虚拟机>>-第三章-垃圾收集器与内存分配策略-学习笔记
    <<深入Java虚拟机>>-第二章-Java内存区域-学习笔记
    创建线程的两种方式比较Thread VS Runnable
    Java设计模式之--代理模式学习
    shell脚本中$参数的介绍
    (转)使用DataTime这个类来获取当前的时间
  • 原文地址:https://www.cnblogs.com/zhenhao1/p/5831701.html
Copyright © 2020-2023  润新知