Codeforces Round #510 (Div. 2) A~F

A. Benches

有$n$个座位,一开始第$i$个座位上有$a_i$个人,之后又来了$m$个人,每个人都可以随便坐到一个座位上

设$f$为最终座位上最多的人数,问$f$的最大值和最小值

$1 \le n \le 100, 1 \le m \le 10000, 1 \le a_i \le 100$

最多的话就是往$a_i$最大的那个位置上坐$m$个人

最少的话就先将所有的座位尽可能填补到$\max a_i$,剩下的人就可以依次坐下了

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 int n, m, a[110];
 5 int main() {
 6     cin >> n >> m;
 7     int mnk, mxk = m;
 8     for(int i = 1 ; i <= n ; ++ i) {
 9         cin >> a[i];
10         mxk = max(mxk, a[i] + m);
11     }
12     sort(a + 1, a + 1 + n);
13     ll sum = 0;
14     for(int i = 1 ; i <= n ; ++ i) sum += a[n] - a[i];
15     if(sum >= m) {
16         mnk = a[n];
17     } else {
18         m -= sum;
19         mnk = a[n] + m / n + (m % n != 0);
20     }
21     cout << mnk << ' ' << mxk << endl; 
22 }
A. Benches

B. Vitamins

有$n$杯果汁,第$i$杯的价钱是$c_i$,每一杯有一个$\{A,B,C}\$的子集,表示它所包含的维生素

你获得一个维生素的前提是喝了至少一被包含这种维生素的果汁

用最小的代价获得所有维生素,如果无解输出$-1$

$1 \le n \le 1000, 1 \le c_i \le 100000$

模拟题意就行了……扔了个装压上去……

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int N = 1010;
 5 int n, ans[10];
 6 int main() {
 7     cin >> n;
 8     memset(ans, 0x3f, sizeof ans);
 9     ans[0] = 0;
10     for(int i = 1, c ; i <= n ; ++ i) {
11         char s[5];
12         cin >> c >> s;
13         int b = 0; for(int j = 0 ; s[j] ; ++ j) b |= 1 << (s[j] - 'A'); 
14         for(int s = 0 ; s < 8 ; ++ s) {
15             for(int t = s ; ~ t ; t = (t - 1) & s) {
16                 if((b | t) == s)
17                     ans[s] = min(ans[s], ans[t] + c);
18                 if(!t) break;
19             }
20         }
21     }
22     cout << (ans[7] == 0x3f3f3f3f ? -1 : ans[7]) << endl;
23 }
B. Vitamins

C. Array Product

有一个由$n$个元素构成的序列$a$,每次你可以选择一对$i,j$,满足$1 \le i \le j \le n, i \not= j$,之后将第$j$个元素变为$a_i \times a_j$,并且删掉第$j$个元素

注意当一个元素被删除后其他元素的下标不变,且这个元素视为不可使用

同时你还可以进行最多一次“特殊操作”,既在任意时刻,无条件删除一个元素

显然在操作$n-1$次之后整个序列只剩下一个元素,最大化这个元素的值,同时输出任何一种方案

$2 \le n \le 2 \times 10^5, -10^9 \le a_i \le 10^9$

 如果没有“特殊操作”的话,这个序列最终的值一定是一个定值,因为只有乘操作,最终相当于将它们合并起来了

一个比较暴力的做法如下:

如果序列中有$0$,那么先通过操作$1$将$0$变为只有$1$个,之后如果小于$0$的数字的个数是奇数,那么先用这个$0$把最大的那个小于$0$的数变为$0$,然后删掉这个$0$,之后再用操作$1$将剩下的元素都拼接起来;如果没有的话就直接删掉$0$,然后剩下的都用操作$1$拼接起来

如果序列中没有$0$,若小于$0$的个数为奇数,就直接删掉最大的那个,剩下的都用操作$1$乘起来;否则直接都乘起来

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int N = 2e5 + 10;
 5 struct T { int a, id; } t[N];
 6 bool cmp(T a, T b) {
 7     return a.a < b.a;
 8 }
 9 int n, tot;
10 void tmp() {
11     -- tot;
12     if(!tot) exit(0);
13 }
14 int main() {
15     ios :: sync_with_stdio(0);
16     cin >> n, tot = n;
17     int cnt0 = 0, cntlt0 = 0, cntgt0 = 0;
18     for(int i = 1 ; i <= n ; ++ i) {
19         cin >> t[i].a, t[i].id = i;
20         if(t[i].a == 0) ++ cnt0;
21         else if(t[i].a < 0) ++ cntlt0;
22         else ++ cntgt0;
23     }
24     sort(t + 1, t + 1 + n, cmp);
25     for(int i = 1 ; i <= n ; ++ i) {
26         if(t[i].a == 0) {
27             for(int j = i + 1 ; j <= n ; ++ j) {
28                 if(t[j].a == 0) {
29                     tmp();
30                     printf("1 %d %d\n", t[j].id, t[i].id);
31                     t[j].a = 1e9 + 10;
32                 } else break;
33             }
34             break;
35         }
36     }
37     sort(t + 1, t + 1 + n, cmp);
38     while(n >= 1 && t[n].a == 1e9 + 10) -- n;
39     if(n) {
40         if(cnt0) {
41             if(cntlt0 & 1) {
42                 for(int i = 1 ; i <= n ; ++ i) {
43                     if(t[i].a == 0) {
44                         if(i - 1 >= 1) {
45                             tmp();
46                             printf("1 %d %d\n", t[i - 1].id, t[i].id);
47                             t[i - 1].a = 1e9 + 10;
48                         }
49                         tmp();
50                         printf("2 %d\n", t[i].id);
51                         t[i].a = 1e9 + 10;
52                         break;
53                     }
54                 }
55             } else {
56                 for(int i = 1 ; i <= n ; ++ i) {
57                     if(t[i].a == 0) {
58                         tmp();
59                         printf("2 %d\n", t[i].id);
60                         t[i].a = 1e9 + 10; 
61                         break;
62                     }
63                 }
64             }
65         } else {
66             if(cntlt0 & 1) {
67                 for(int i = n ; i ; -- i) {
68                     if(t[i].a < 0) {
69                         tmp();
70                         printf("2 %d\n", t[i].id);
71                         t[i].a = 1e9 + 10;
72                         break;
73                     }
74                 }
75             }
76         }
77         sort(t + 1, t + 1 + n, cmp);
78         while(n >= 1 && t[n].a == 1e9 + 10) -- n;
79         for(int i = 1 ; i < n ; ++ i) {
80             int x = t[i + 1].id;
81             tmp(); 
82             printf("1 %d %d\n", t[i].id, x);
83         }
84     }
85 }
C. Array Product

D. Petya and Array

给定一个序列,问有多少连续子序列的和小于$t$

$1 \le n \le 200000, |t| \le 2 \times 10^{14}, |a_i| \le 10^9$

求一下前缀和$s$,也就是$s_i-s_j \le t-1 \to s_j \ge t-1-s_i$

离散化后树状数组查询前/后缀和就行了

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int N = 2e5 + 10;
 5 int n; ll a[N], s[N], t;
 6 vector<ll> num;
 7 int get(ll n) {
 8     return lower_bound(num.begin(), num.end(), n) - num.begin() + 1;
 9 }
10 int bit[int(1e6)];
11 void add(int x) {
12     for( ; x <= num.size() + 10 ; x += x & -x)
13         ++ bit[x]; 
14 }
15 int ask(int x) {
16     int r = 0;
17     for( ; x ; x -= x & -x) r += bit[x];
18     return r;
19 }
20 
21 int main() {
22     ios :: sync_with_stdio(0), cin.tie(0), cout.tie(0);
23     cin >> n >> t; -- t;
24     num.push_back(0);
25     for(int i = 1 ; i <= n ; ++ i) cin >> a[i], s[i] = s[i - 1] + a[i], num.push_back(s[i]), num.push_back(s[i] - t - 1);
26     sort(num.begin(), num.end());
27     add(get(0));
28     ll ans = 0;
29     for(int i = 1 ; i <= n ; ++ i) {
30         ans += i - ask(get(s[i] - t - 1));
31         add(get(s[i]));
32     }
33     cout << ans << endl;
34 }
D. Petya and Array

E. Vasya and Magic Matrix

给定一个$n \times m$的矩阵$a$,每个位置都有一个值$a_{i,j}$,对于每一个点$(i,j)$,它可以走到一个小于$a_{i,j}$的位置(等概率的),设其为$(x,y)$,同时花费$(x-i)^2+(y-j)^2$的代价,然后继续这个过程,直到走不动了

同时给$(r,c)$,问在$(r,c)$时花费的代价的期望

$1 \le n,m \le 1000, 0 \le a_{i,j} \le 10^9, 1 \le r \le n, 1 \le m \le c$

如果直接做我是不会的……

由于有关于$a$的大小限制,那么不妨尝试一种套路——按照$a$升序排序,然后依次填入到矩阵中

假设当前考虑到了$(x,y)$, 之前已经填入了$k$个节点,那么当前点的答案就是

$$ \begin{aligned} &\frac{1}{k}\sum_{i=1}^{k}f_{i}+(x_i-x)^2+(y_i-y)^2 \\ =&\frac{1}{k}\sum_{i=1}^{k}f_{i}+x_i^2+x^2-2xx_i+y_i^2+y^2-2yy_i \\ =&\frac{(\sum_{i=1}^{k}f_{i})+(\sum_{i=1}^{k}x_i^2)+kx^2-2x(\sum_{i=1}^{k}x_i)+(\sum_{i=1}^{k}y_i^2)+ky^2-2y(\sum_{i=1}^{k}y_i)}{k} \end{aligned} $$

然后做完了……动态维护一下这几个变量就行了……

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int N = 1010, mod = 998244353;
 5 int n, m, r, c; struct P {int val, x, y; } p[N * N];
 6 bool operator < (P a, P b) { return a.val < b.val; }
 7 ll f[N * N], Ti, Tj, Tii, Tjj, sum, cnt;
 8 ll pw(ll a, ll b) {
 9     ll r = 1;
10     for( ; b ; b >>= 1, a = a * a % mod)
11         if(b & 1)
12             r = r * a % mod;
13     return r;
14 }
15 
16 ll pls(ll a = 0, ll b = 0, ll c = 0) {
17     return ((a + b) % mod + c) % mod; 
18 }
19 
20 int main() {
21     ios :: sync_with_stdio(0);
22     cin >> n >> m; int tot = 0;
23     for(int i = 1 ; i <= n ; ++ i)
24         for(int j = 1 ; j <= m ; ++ j)
25             cin >> p[++ tot].val, p[tot].x = i, p[tot].y = j;
26     cin >> r >> c;
27     sort(p + 1, p + 1 + tot);
28     for(int i = 1 ; i <= tot ; ++ i) {
29         ll p1 = sum;
30         ll p2 = Tii;
31         ll p3 = Tjj;
32         ll p4 = 1ll * cnt * p[i].x % mod * p[i].x % mod;
33         ll p5 = 1ll * cnt * p[i].y % mod * p[i].y % mod;
34         ll p6 = -2ll * p[i].x % mod * Ti % mod;
35         ll p7 = -2ll * p[i].y % mod * Tj % mod;
36         f[i] = pls(pls(p1, p2, p3), pls(p4, p5), pls(p6, p7)) * pw(cnt, mod - 2) % mod;
37         if(p[i].x == r && p[i].y == c) {
38             f[i] = (f[i] % mod + mod) % mod;
39             cout << f[i] << endl;
40             exit(0);
41         }
42         if(p[i].val != p[i + 1].val) {
43             for(int j = i ; j >= 1 ; -- j) {
44                 if(p[j].val != p[i].val) break;
45                 Ti += p[j].x, Tj += p[j].y;
46                 Tii += 1ll * p[j].x * p[j].x % mod, Tjj += 1ll * p[j].y * p[j].y % mod;
47                 Ti %= mod, Tj %= mod, Tii %= mod, Tjj %= mod;
48                 sum += f[j], sum %= mod;
49                 ++ cnt;
50             }
51         }
52     }
53 }
E. Vasya and Magic Matrix

F. Leaf Sets

给定一棵$n$个节点的无根树,将它的叶子分成若干块,使得每一块叶子的两两之间距离的最大值不超过$k$

最小化分割的块数

$3 \le n \le 10^6, 1 \le k \le 10^6$

首先需要找到一个非叶子结点,然后用这个节点当作根开始$dfs$

每个节点都维护一个$multiset$,表示每一块的最深深度

然后直接启发式合并一下就行了……

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int N = 1e6 + 10;
 5 multiset<int> s[N];
 6 int n, k; vector<int> g[N];
 7 void dfs(int u, int fa, int dep) {
 8     if(g[u].size() == 1) return s[u].insert(dep), void();
 9     int c = 0; for(int v: g[u])
10         if(v != fa)
11             dfs(v, u, dep + 1),
12             (c == 0 || s[c].size() < s[v].size() ? (c = v) : 0);
13     swap(s[c], s[u]);
14     for(int v: g[u])
15         if(v != fa && v != c)
16             for(int d: s[v]) {
17                 int x = k + 2 * dep - d;
18                 auto it = s[u].upper_bound(x);
19                 if(it == s[u].begin()) s[u].insert(d);
20                 else {
21                     int x = * -- it;
22                     s[u].erase(it);
23                     s[u].insert(max(x, d));
24                 }
25             } 
26 }
27 int main() {
28     ios :: sync_with_stdio(0);
29     cin >> n >> k;
30     for(int i = 1, u, v ; i < n ; ++ i)
31         cin >> u >> v,
32         g[u].push_back(v),
33         g[v].push_back(u);
34     for(int i = 1 ; i <= n ; ++ i)
35         if(g[i].size() >= 2)
36             return dfs(i, 0, 0),
37             printf("%d\n", int(s[i].size())), 0;
38 }
F. Leaf Sets

posted @ 2018-09-17 20:47  KingSann  阅读(136)  评论(0编辑  收藏  举报