zoukankan      html  css  js  c++  java
  • Codeforces Round #520 (Div. 2) Solution

    A. A Prank

    Solved.

    题意:

    给出一串数字,每个数字的范围是$[1, 1000]$,并且这个序列是递增的,求最多擦除掉多少个数字,使得别人一看就知道缺的数字是什么。

    思路:

    显然,如果缺的这块数字的个数刚好等于右界 - 左界 + 1 那么就可以知道

    还需要考虑数据范围,因为是$<= 1000  和 >= 1$ 那么对于两边的边界需要特殊考虑。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 #define N 110
     5 int n, a[N];
     6 
     7 int main()
     8 {
     9     while (scanf("%d", &n) != EOF)
    10     {
    11         for (int i = 1; i <= n; ++i) scanf("%d", a + i);
    12         a[0] = 0; a[n + 1] = 1001;
    13         int res = 0, tmp = 1;
    14         for (int i = 1; i <= n + 1; ++i)
    15         {
    16             if (a[i] == a[i - 1] + 1) ++tmp;
    17             else
    18             {
    19                 res = max(res, tmp - 2);
    20                 tmp = 1;
    21             }
    22         }
    23         res = max(res, tmp - 2);
    24         printf("%d
    ", res);
    25     }
    26     return 0;
    27 }
    View Code

    B. Math

    Solved.

    题意:

    给出一个数$n$, 有两种操作。

    第一种是乘上一个任意整数$x$

    第二种是开方,并且要保证开方后是整数。

    求最少经过多少次操作,可以得到一个最小的数$n$

    思路:

    考虑$n$的质因数分解形式$a_1^{p_1} cdot a_2^{p_2} cdot a_3^{p_3} ...$

    那么最小的答案就是$a_1 cdot a_2 cdot a_3$

    因为一个数开方后是整数的话,显然是每个质因子的幂次都是偶数次,开方相当于每个质因子的幂次 $ / 2$

    那么显然每个质因子最小的幂次都是1

    再考虑最小的次数,因为乘法可以任意乘一个整数,所以如果需要乘法,那么乘法只需要一次。

    再考虑开方,如果质因子中的最高幂次不是2的幂次,那么它不断$ / 2$ 肯定需要至少一次乘法操作,使得可以继续开方下去,直到幂次变为1

    那么显然要把幂次变成一个第一个大于等于它的2的幂次数,就可以不断$ / 2$

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 #define N 2000010
     5 int n, Max, res;
     6 int Bit[N], pos[N];
     7 vector <int> v;
     8 
     9 int solve(int x)
    10 {
    11     if (x == 1) return 0;
    12     if (pos[x] == 0) return 1 + lower_bound(Bit + 1, Bit + 1 + 20, x) - Bit; 
    13     for (auto it : v) if (it != x) return 1 + pos[x];
    14     return pos[x];
    15 }
    16 
    17 int main()
    18 {
    19     Bit[0] = 1; pos[1] = 0;  
    20     for (int i = 1; i <= 20; ++i)
    21     {
    22         Bit[i] = Bit[i - 1] << 1;
    23         pos[Bit[i]] = i;
    24     }    
    25     while (scanf("%d", &n) != EOF)
    26     {
    27         if (n == 1) 
    28         {
    29             puts("1 0");
    30             continue;
    31         }
    32         v.clear();
    33         res = 1; Max = 0;
    34         for (int i = 2; i <= n; ++i) 
    35         {
    36             int tmp = 0; 
    37             while (n % i == 0)
    38             { 
    39                 ++tmp; 
    40                 n /= i;
    41             }
    42             if (tmp) 
    43             {
    44                 res *= i;
    45                 Max = max(Max, tmp);
    46                 v.push_back(tmp); 
    47             }
    48         }    
    49         printf("%d %d
    ", res, solve(Max));
    50     }
    51     return 0;
    52 }
    View Code

    C. Banh-mi

    Solved.

    题意:

    给出一个01串,每次询问区间$[l, r]$ 每次可以将区间内一个数取出,并且答案加上这个数的值,区间内剩余的数也加上这个值,求如何安排取出顺序使得答案最大。

    思路:

    显然1要在0之前取,

    我们考虑区间内有$x个1, y 个 0$

    那么考虑取出$x个1的答案$

    显然 取出的数是形如 1 2 4 8 .....

    是一个等比数列,根据求和公式发现答案为$2^x - 1$

    再考虑取出的第一个0的数值为 $2^x - 1$

    也是一个等比数列,和为 $(2^x - 1) cdot (2^y - 1)$

    合并两项答案   即$2^x cdot (2^y - 1)$

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 #define ll long long
     5 #define N 100010
     6 const ll MOD = (ll)1e9 + 7;
     7 int n, q, a[N];
     8 
     9 ll qmod(ll base, ll n)
    10 {
    11     ll res = 1;
    12     while (n)
    13     {
    14         if (n & 1) res = res * base % MOD;
    15         base = base * base % MOD;
    16         n >>= 1;
    17     }
    18     return res;
    19 }
    20 
    21 int main()
    22 {
    23     while (scanf("%d%d", &n, &q) != EOF)
    24     {
    25         a[0] = 0;
    26         for (int i = 1; i <= n; ++i) scanf("%1d", a + i), a[i] += a[i - 1];
    27         for (int i = 1, l, r; i <= q; ++i) 
    28         {
    29             scanf("%d%d", &l, &r);
    30             int x = a[r] - a[l - 1], y = (r - l + 1) - x;
    31             if (x == 0) 
    32             {
    33                 puts("0");
    34                 continue;
    35             }
    36             printf("%lld
    ", qmod(2, y) * (qmod(2, x) - 1 + MOD) % MOD);
    37         }
    38     }
    39     return 0;
    40 }
    View Code

    D. Fun with Integers

    Solved.

    题意:给出一个数$n$,任意$|a| , |b| < n$ 并且满足 $|a| |b| 互为倍数关系$ 那么答案加上这个倍数,并且这一对$|a|, |b|$不再提供贡献,并且倍数关系$|x| > 1$

    思路:

    考虑一个数$x$, 那么在$[1, n]$ 中是它的倍数的数一共有 $y = lfloor frac {n}{x} floor cdot 2$ 个 因为还有负的

    那么这个数的贡献是$sum_2 ^y  cdot 2$ 再考虑 $-x$ 也会提供一样的贡献 即答案要乘2

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 #define ll long long
     5 int n;
     6 
     7 int main()
     8 {
     9     while (scanf("%d", &n) != EOF)
    10     {
    11         ll res = 0;
    12         for (int i = 2; i <= n; ++i)
    13         {
    14             ll x = n / i;
    15             res += 2ll * (x + 2) * (x - 1);
    16         }
    17         printf("%lld
    ", res);
    18     }
    19     return 0;
    20 }
    View Code

    E. Company

    Upsolved.

    题意:

    在一棵树中,每次选择一个区间$[l, r]$ 最多删除一个点,使得这个区间内所有点的$lca$ 的深度最大。

    思路:

    首先有一个点,就是一颗树中一堆点的$LCA$ 其实就是这堆点$DFS序最小 和 最大的两个点的LCA$

    不难证明:

    $我们约定用st[u] 表示点u的DFS序编号,并且约定 st[x] < st[y] <st[z], $

    $根据ST求LCA 显然两个点的LCA是 st[x] 和 st[y] 中间DFS序最小的点,那么再考虑 一个点z $

    $ 此处我们再对z求lca ,普通做法显然是 用st[lca(x, y)]  - st[z] 之间找一个最小的$

    $但实际上没有必要从st[(lca(x, y))] 开始,直接从 st[x] - st[y] 这段中找到的 pos = lca(x, y) 的位置作为左界即可$

    $因为考虑 从st[lca(x, y)] - pos 这一段中,不会有DFS序编号比lca(x, y) 还要小的点,因为显然这一段序列都是在lca(x, y) 的子树中$

    $如此看来,我们约定用u 表示 [l, r] 中DFS序编号最小的点,v 表示编号最大的点$

    $那么LCA 就是 从 st[u] - st[v] 中找一个最小点 即为LCA$

    $再考虑移除哪一个点,我们知道答案跟一段序列的最小值有关,我们要让答案有变化,要让这一段序列的区间长度有变化$

    $显然是移除左边的一个点或者右边的一个点 即 DFS序编号最大的点 或者 DFS序编号最小的点$

      1 #include <bits/stdc++.h>
      2 using namespace std;
      3 
      4 #define INF 0x3f3f3f3f
      5 #define N 100010
      6 int n, q, l, r;
      7 vector <int> G[N];
      8 
      9 int p[N], fp[N], sze[N], son[N], fa[N], deep[N], top[N], cnt;
     10 void DFS(int u)
     11 {
     12     sze[u] = 1;
     13     for (auto v : G[u]) if (v != fa[u])
     14     {
     15         fa[v] = u;
     16         deep[v] = deep[u] + 1;
     17         DFS(v); sze[u] += sze[v];
     18         if (!son[u] || sze[v] > sze[son[u]]) son[u] = v;
     19     }
     20 }
     21 
     22 void getpos(int u, int sp = 1)
     23 {
     24     top[u] = sp;
     25     p[u] = ++cnt;
     26     fp[cnt] = u;
     27     if (!son[u]) return;
     28     getpos(son[u], sp);
     29     for (auto v : G[u]) if (v != son[u] && v != fa[u])
     30         getpos(v, v);
     31 }
     32 
     33 int querylca(int u, int v)
     34 {
     35     while (top[u] != top[v])
     36     {
     37         if (deep[top[u]] < deep[top[v]]) swap(u, v);
     38         u = fa[top[u]];
     39     }
     40     if (deep[u] > deep[v]) swap(u, v);
     41     return u;
     42 }
     43 
     44 struct SEG
     45 {
     46     struct node
     47     {
     48         int Max, Min;
     49         void init() { Max = 0, Min = INF; }
     50         node operator + (const node &r) const
     51         {
     52             node res; res.init();
     53             res.Max = max(Max, r.Max);
     54             res.Min = min(Min, r.Min);
     55             return res;    
     56         }
     57     }a[N << 2], res; 
     58     void build(int id, int l, int r)
     59     {
     60         a[id].init();
     61         if (l == r)
     62         {
     63             a[id].Max = a[id].Min = p[l];
     64             return;
     65         }
     66         int mid = (l + r) >> 1;
     67         build(id << 1, l, mid);
     68         build(id << 1 | 1, mid + 1, r);
     69         a[id] = a[id << 1] + a[id << 1 | 1];
     70     }
     71     void query(int id, int l, int r, int ql, int qr)
     72     {
     73         if (l >= ql && r <= qr) 
     74         {
     75             res = res + a[id];
     76             return;
     77         }
     78         int mid = (l + r) >> 1;
     79         if (ql <= mid) query(id << 1, l, mid, ql, qr);
     80         if (qr > mid) query(id << 1 | 1, mid + 1, r, ql, qr);
     81     }
     82 }seg;
     83 
     84 int lca(int l, int r)
     85 {
     86     seg.res.init();
     87     seg.query(1, 1, n, l, r);
     88     return querylca(fp[seg.res.Min], fp[seg.res.Max]);
     89 }
     90 
     91 int work(int x)
     92 {
     93     if (x == l) return deep[lca(l + 1, r)];
     94     if (x == r) return deep[lca(l, r - 1)];
     95     return deep[querylca(lca(l, x - 1), lca(x + 1, r))]; 
     96 }
     97 
     98 void init()
     99 {
    100     for (int i = 1; i <= n; ++i) G[i].clear();
    101     memset(son, 0, sizeof son);
    102     cnt = 0; fa[1] = 0; deep[1] = 0;
    103 }
    104 
    105 int main()
    106 {
    107     while (scanf("%d%d", &n, &q) != EOF)
    108     {
    109         init();
    110         for (int u = 2, v; u <= n; ++u)
    111         {
    112             scanf("%d", &v);
    113             G[u].push_back(v);
    114             G[v].push_back(u);
    115         }
    116         DFS(1); getpos(1); seg.build(1, 1, n);
    117         //for (int i = 1; i <= n; ++i) printf("%d %d %d
    ", i, p[i], fp[i]);
    118         for (int qq = 1; qq <= q; ++qq)
    119         {
    120             scanf("%d%d", &l, &r);
    121             seg.res.init(); seg.query(1, 1, n, l, r);
    122             int x = fp[seg.res.Max], y = fp[seg.res.Min];
    123             int deepx = work(x), deepy = work(y);
    124             if (deepx > deepy) printf("%d %d
    ", x, deepx);
    125             else printf("%d %d
    ", y, deepy); 
    126         }
    127     }
    128     return 0;
    129 }
    View Code

    F. Upgrading Cities

    Unsolved.

  • 相关阅读:
    9.10 作业
    Day 03 作业
    Day02作业
    Day09 函数
    day08 简单习题
    Day04 python数据类型和词云的生成
    JAVA: 子类通过static块“覆盖”父类的成员变量风险
    JAVA: 子类“覆盖”父类的成员变量
    Java 访问控制权限
    Java数组类型转为集合类型
  • 原文地址:https://www.cnblogs.com/Dup4/p/9961478.html
Copyright © 2011-2022 走看看