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\n", 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\n", res);
47     }    
48     return 0;
49 }
View Code

 

 

C. Maximum Subrectangle

Solved.

题意:

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

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

思路:

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

$\sum\limits_{i = x_1}^{x_2} \sum\limits_{i = y_1}^{y_2} c_{i, j} = $

$\sum\limits_{i = x_1}^{x_2} \sum\limits_{i = y_1}^{y_2} a_i \cdot b_j = $

$\sum\limits_{i = x_1}^{x_2} a_i \cdot \sum\limits_{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\n", 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\n", 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\n", res / 2);
113     }
114     return 0;
115 }
View Code

 

posted @ 2019-02-12 07:46  Dup4  阅读(173)  评论(0编辑  收藏  举报