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 }
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 }
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 }
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 }
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 }