• Codeforces Round #513 by Barcelona Bootcamp


    A. Phone Numbers

    签.

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

    B. Maximum Sum of Digits

    Solved.

    题意:

    将一个数拆成$a + b = n$

    $要求S(a) + S(b)最大$

    $定义S(x) 为x的各位数字之和(以十进制表示)$

    思路:

    贪心构造一个数字$a有尽量多的9并且小于n即可$

    $为什么这样是对的$

    我们假设最优解为$a, b$

    $令a_i, b_i表示a, b的第i位$

    $如果存在某个a_i,不是9, 那么我们将它改成9$

    $那么对b_i的影响就是要减去差值$

    $如果造成退位,那么答案更优$

    $如果没有退位,那么答案不变$

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 #define ll long long
     5 ll n;
     6 
     7 int f(ll x)
     8 {
     9     int res = 0;
    10     while (x)
    11     {
    12         res += x % 10;
    13         x /= 10;
    14     }
    15     return res;
    16 }
    17 
    18 int main()
    19 {
    20     while (scanf("%lld", &n) != EOF)
    21     {
    22         int res = 0;
    23         if (n <= 1000000) 
    24         {
    25             for (int i = 0; i <= n; ++i) 
    26                 res = max(res, f(i) + f(n - i));        
    27         }
    28         else
    29         {
    30             ll tmp = n;
    31             string s = "";
    32             while (tmp)
    33             {
    34                 if (tmp / 10) s += '9';
    35                 else if (tmp > 1) s += tmp - 1 + '0';
    36                 tmp /= 10;
    37             }
    38             ll x = 0;
    39             reverse(s.begin(), s.end());
    40             for (int i = 0, len = s.size(); i < len; ++i) x = x * 10 + s[i] - '0';
    41             res = f(x) + f(n - x);
    42             ll mid = n / 2; 
    43             for (ll i = max(0ll, mid - 1000000); i <= min(n, mid + 1000000); ++i)
    44                 res = max(res, f(i) + f(n - i));
    45         }
    46         printf("%d
    ", res);
    47     }    
    48     return 0;
    49 }
    View Code

    C. Maximum Subrectangle

    Solved.

    题意:

    有一个矩阵$c_{i, j} = a_i cdot b_j$

    $求一个最大子矩阵使得sumlimits_{i = x_1}^{x_2} sumlimits_{i = y_1}^{y_2} c_{i, j} <= x$

    思路:

    我们考虑将求和的式子变换一下

    $sumlimits_{i = x_1}^{x_2} sumlimits_{i = y_1}^{y_2} c_{i, j} = $

    $sumlimits_{i = x_1}^{x_2} sumlimits_{i = y_1}^{y_2} a_i cdot b_j = $

    $sumlimits_{i = x_1}^{x_2} a_i cdot sumlimits_{i = y_1}^{y_2} b_j $

    那么我们要想使面积最大

    只要先预处理出长度为$x的子段和最小的a[] 和 长度为y的字段和最小的b[]$

    $再枚举x, y更新答案即可$

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 #define ll long long
     5 #define N 2010
     6 int n, m, a[N], b[N];
     7 ll x;
     8 int f[N], g[N];
     9 
    10 int main()
    11 {
    12     while (scanf("%d%d", &n, &m) != EOF)
    13     {
    14         for (int i = 1; i <= n; ++i) scanf("%d", a + i), a[i] += a[i - 1];
    15         for (int i = 1; i <= m; ++i) scanf("%d", b + i), b[i] += b[i - 1];
    16         scanf("%lld", &x);
    17         memset(f, 0x3f, sizeof f);
    18         memset(g, 0x3f, sizeof g);
    19         for (int i = 1; i <= n; ++i)
    20             for (int j = i; j <= n; ++j)
    21                 f[j - i + 1] = min(f[j - i + 1], a[j] - a[i - 1]);
    22         for (int i = 1; i <= m; ++i)
    23             for (int j = i; j <= m; ++j)
    24                 g[j - i + 1] = min(g[j - i + 1], b[j] - b[i - 1]);
    25         int res = 0;
    26         for (int i = 1; i <= n; ++i)
    27             for (int j = 1; j <= m; ++j)
    28                 if (1ll * f[i] * g[j] <= x)
    29                     res = max(res, i * j);
    30         printf("%d
    ", res);
    31     }
    32     return 0;
    33 }
    View Code

    D. Social Circles

    Solved.

    题意:

    有$n个人,要坐在若干个圆桌上,每个人要求左边和右边至少有l_i 和r_i个空凳子$

    $空凳子部分可以交叉$

    至少需要几张凳子

    思路:

    我们考虑答案就是$sum l_i + sum r_i + n - 交叉部分$

    $那么我们就是尽量让交叉部分大即可$

    $那么右边空凳子需求多的要和左边空凳子需求多的相邻即可$

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

    E. Sergey and Subway

    Solved.

    题意:

    给出一棵树

    $现在如果有两个点共同邻接另外一个点$

    $那么就给这两个点连一条边$

    求新图中所有点对之间的最短距离

    思路:

    我们考虑新图中两点之间距离和原图之间的关系

    $我们考虑下面这样的$

    $1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8$

    $我们用dis[x] 表示x -> 1的距离$

    $在原图中$

    $dis_2 = 1, dis_3 = 2, dis_4 = 3, dis_5 = 4, dis_6 = 5, dis_7 = 6, dis_8 = 7$

    在新图中

    $dis_2 = 1, dis_3 = 1, dis_4 = 2, dis_5 = 2, dis_6 = 3, dis_7 = 3, dis_8 = 4$

    $我们发现新图和原图中距离的关系是$

    $dis_新 = (dis_原 + 1) / 2$

    $用线段树维护原图距离以及奇数个数再树形dp即可$

      1 #include <bits/stdc++.h>
      2 using namespace std;
      3 
      4 #define ll long long
      5 #define N 200010
      6 int n;
      7 vector <int> G[N];
      8 
      9 namespace SEG
     10 {
     11     struct node
     12     {
     13         ll a, b, lazy, cnt;
     14         void init()
     15         {
     16             a = b = lazy = cnt = 0;
     17         }
     18         void add(ll x)
     19         {
     20             a += x * cnt;
     21             lazy += x;
     22             if (abs(x) % 2)
     23                 b = cnt - b;
     24         }
     25         ll f()
     26         {
     27             return (a + b) / 2; 
     28         }
     29         node operator + (const node &other) const
     30         {
     31             node res; res.init();
     32             res.a = a + other.a;
     33             res.b = b + other.b;
     34             res.cnt = cnt + other.cnt;
     35             return res;
     36         }
     37     }a[N << 2];
     38     void build(int id, int l, int r)
     39     {
     40         a[id].init();
     41         a[id].cnt = r - l + 1;
     42         if (l == r) return;
     43         int mid = (l + r) >> 1;
     44         build(id << 1, l, mid);
     45         build(id << 1 | 1, mid + 1, r);
     46     }
     47     void pushdown(int id)
     48     {
     49         if (!a[id].lazy) return;
     50         a[id << 1].add(a[id].lazy);
     51         a[id << 1 | 1].add(a[id].lazy);
     52         a[id].lazy = 0;
     53     }
     54     void update(int id, int l, int r, int ql, int qr, int val)
     55     {
     56         if (l >= ql && r <= qr)
     57         {
     58             a[id].add(val);
     59             return;
     60         }
     61         int mid = (l + r) >> 1;
     62         pushdown(id);
     63         if (ql <= mid) update(id << 1, l, mid, ql, qr, val);
     64         if (qr > mid) update(id << 1 | 1, mid + 1, r, ql, qr, val);
     65         a[id] = a[id << 1] + a[id << 1 | 1];
     66     }
     67 }
     68 
     69 int fa[N], deep[N], in[N], out[N], cnt;
     70 void DFS(int u)
     71 {
     72     in[u] = ++cnt;
     73     for (auto v : G[u]) if (v != fa[u])
     74     {
     75         fa[v] = u;
     76         deep[v] = deep[u] + 1;
     77         DFS(v);
     78     }
     79     out[u] = cnt;
     80 }
     81 
     82 ll res;
     83 void DFS2(int u)
     84 {
     85     res += SEG::a[1].f();
     86     for (auto v : G[u]) if (v != fa[u])
     87     {
     88         SEG::update(1, 1, n, 1, n, 1);
     89         SEG::update(1, 1, n, in[v], out[v], -2);
     90         DFS2(v);
     91         SEG::update(1, 1, n, 1, n, -1);
     92         SEG::update(1, 1, n, in[v], out[v], 2);
     93     }
     94 }
     95 int main()
     96 {
     97     while (scanf("%d", &n) != EOF)
     98     {
     99         cnt = 0; res = 0;
    100         for (int i = 1; i <= n; ++i) G[i].clear();
    101         for (int i = 1, u, v; i < n; ++i)
    102         {
    103             scanf("%d%d", &u, &v);
    104             G[u].push_back(v);
    105             G[v].push_back(u);
    106         }
    107         deep[1] = 0;
    108         DFS(1);
    109         SEG::build(1, 1, n);
    110         for (int i = 1; i <= n; ++i) SEG::update(1, 1, n, in[i], in[i], deep[i]);
    111         DFS2(1);
    112         printf("%lld
    ", res / 2);
    113     }
    114     return 0;
    115 }
    View Code
  • 相关阅读:
    2020/7/18 JDBC
    2020.8.1
    2020.7.31
    二元泰勒公式
    一元泰勒公式
    极值
    介值定理
    积分上限函数
    积分中值定理
    狄利克雷(Dirichlet)函数
  • 原文地址:https://www.cnblogs.com/Dup4/p/10363805.html
Copyright © 2020-2023  润新知