我是靠谱客的博主 天真香菇,这篇文章主要介绍Codeforces Round #791 (Div. 2)(A-D)Codeforces Round #791 (Div. 2)(A-D),现在分享给大家,希望可以做个参考。

Codeforces Round #791 (Div. 2)(A-D)

A. AvtoBus

题意:

给你 n, 问满足 4 x + 6 y = n 4x+6y=n 4x+6y=n x + y x+y x+y的最小值和最大值是多少? x , y x,y x,y 都是非负整数。

题解:

n如果是奇数,无解。如果是偶数,等式除以2,考虑 2 x + 3 y = n 2x+3y=n 2x+3y=n

要想使得 x + y x+y x+y尽可能大,那么x要尽量多,就需要找最小的y满足 n − 3 y n-3y n3y是偶数,分别讨论摸3的各种情况。反之同理。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int, int> pii; const int MAXN = 1e5 + 10; const int MOD = 1e9 + 7; int main() { #ifdef LOCAL freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout); #endif ios::sync_with_stdio(false), cin.tie(0); int t; ll n; cin >> t; while (t--) { cin >> n; if (n & 1 || n == 2) { cout << -1 << endl; continue; } n /= 2; ll mi = 1e9, mx = 0; if (n < 4) { cout << "1 1" << endl; continue; } switch (n % 3) { case 0: mi = n / 3; break; case 1: mi = (n - 4) / 3 + 2; break; case 2: mi = (n - 2) / 3 + 1; break; default: break; } if (n & 1) { mx = max(mi, 1 + (n - 3) / 2); } else { mx = max(mi, n / 2); } cout << mi << ' ' << mx << endl; } return 0; }

B. Stone Age Problem

题意:

给你 长度为 n n n的数组 a a a, 有两种操作:

  1. a i a_i ai改成 x x x
  2. 把所有数改成 x x x

输出每次操作后

题解:

单点更新,区间更新,维护区间和,这不就是线段树吗,练板子了。。。。当然,这里是区间赋值

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int, int> pii; const int MAXN = 2e5 + 10; const int MOD = 1e9 + 7; int n, q, a[MAXN]; struct node { int l, r; ll lazy; ll sum; } tr[MAXN << 2]; inline int lson(int x) { return x << 1; } inline int rson(int x) { return x << 1 | 1; } void pushup(int x) { tr[x].sum = tr[lson(x)].sum + tr[rson(x)].sum; } void pushdown(int x) { if (tr[x].lazy) { tr[lson(x)].lazy = tr[x].lazy; tr[rson(x)].lazy = tr[x].lazy; tr[lson(x)].sum = (tr[lson(x)].r - tr[lson(x)].l + 1) * tr[x].lazy; tr[rson(x)].sum = (tr[rson(x)].r - tr[rson(x)].l + 1) * tr[x].lazy; tr[x].lazy = 0; } } void build(int x, int l, int r) { tr[x].l = l, tr[x].r = r, tr[x].lazy = 0; if (l == r) { return; } int mid = l + r >> 1; build(lson(x), l, mid); build(rson(x), mid + 1, r); pushup(x); } ll query(int x, int l, int r) { if (tr[x].l >= l && tr[x].r <= r) return tr[x].sum; if (tr[x].l > r || tr[x].r < l) return 0; pushdown(x); return query(lson(x), l, r) + query(rson(x), l, r); } void update(int x, int l, int r, ll k) { if (tr[x].l >= l && tr[x].r <= r) { tr[x].lazy = k; tr[x].sum = (tr[x].r - tr[x].l + 1) * k; return; } if (tr[x].l > r || tr[x].r < l) return; pushdown(x); update(lson(x), l, r, k); update(rson(x), l, r, k); pushup(x); } int main() { #ifdef LOCAL freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout); #endif ios::sync_with_stdio(false), cin.tie(0); cin >> n >> q; build(1, 1, n); for (int i = 1; i <= n; i++) { int a; cin >> a; update(1, i, i, a); } while (q--) { int t, x, i; cin >> t; if (t == 1) { cin >> i >> x; update(1, i, i, x); } else { cin >> x; update(1, 1, n, x); } cout << query(1, 1, n) << endl; } return 0; }

C. Rooks Defenders

题意:

给你 n*n的国际象棋棋盘,有3种操作:

  1. ( i , j ) (i,j) (i,j)处放一个车
  2. 移除 ( i , j ) (i,j) (i,j)处的车
  3. 查询矩形 ( x 1 , y 1 ) , ( x 2 , y 2 ) (x_1,y_1), (x_2,y_2) (x1,y1),(x2,y2)的所有点是不是都被车攻击到

题解:

用两个树状数组维护行和列能不能被车吃到,放子的时候,注意幂等,也就是说,这一行/列如果已经被车吃到了,就不用放了。

也可以用线段树做,维护区间最小值。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#include <bits/stdc++.h> using namespace std; #define int long long typedef pair<int, int> pii; const int MAXN = 2e5 + 10; const int MOD = 1e9 + 7; int n, q; int tr1[MAXN], tr2[MAXN]; int r[MAXN], c[MAXN]; inline int lowbit(int x) { return x & (-x); } void add(int* tr, int i, int d) { while (i <= n) { tr[i] += d; i += lowbit(i); } } int sum(int* tr, int i) { int res = 0; while (i > 0) { res += tr[i]; i -= lowbit(i); } return res; } signed main() { #ifdef LOCAL freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout); #endif ios::sync_with_stdio(false), cin.tie(0); int t; int x, y, x1, x2, y1, y2; cin >> n >> q; while (q--) { cin >> t; if (t == 1) { cin >> x >> y; r[x]++, c[y]++; if (r[x] == 1) add(tr1, x, 1); if (c[y] == 1) add(tr2, y, 1); } else if (t == 2) { cin >> x >> y; r[x]--, c[y]--; if (r[x] == 0) add(tr1, x, -1); if (c[y] == 0) add(tr2, y, -1); } else { cin >> x1 >> y1 >> x2 >> y2; bool row = sum(tr1, x2) - sum(tr1, x1 - 1) >= x2 - x1 + 1; bool col = sum(tr2, y2) - sum(tr2, y1 - 1) >= y2 - y1 + 1; puts((row || col) ? "Yes" : "No"); } } return 0; }

D.Toss a Coin to Your Graph…

题意:

给你一个图,选择一条长度为 k − 1 k-1 k1的路径,使得沿路k个点的点权的最大值最小

题解:

看到最X值最X,刻在DNA里就是“二分答案“,那么我们可以看出答案最大值为点权最大值1e9,最小值为0,二分答案记为mid,则问题转化为:

是否存在一条长度为 k − 1 k-1 k1 的路径,使得沿路k个点的点权不超过 m i d mid mid ?

可以想到,如果存在,那么这条路径经过的点的点权都不超过mid,那就一定在原图里面点权小于mid的子图里面,则问题可以进一步转化为:

给你一个图,是否存在长度为 k − 1 k-1 k1的路径?

这样问题就变得容易解决了,首先如果有环,一定存在任意长度的路径。

否则是个dag图,拓扑排序的时候记录dp[i]表示从入度为0的点走到i点的最长路径,如果走到了k,则直接返回true,否则拓扑排序出来之后判断是否仍有入度不为0的点,如果有,说明一定存在环,若存在环,就说明任意长度的路径都存在,返回true,否则为false。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int, int> pii; const int MAXN = 2e5 + 10; const int MOD = 1e9 + 7; int n, m; ll k; ll a[MAXN]; vector<int> g[MAXN]; int in[MAXN]; bool vis[MAXN]; int dp[MAXN]; // 建一个新图 vector<int> g2[MAXN]; unordered_set<int> s; // if exists path which max number of it <= x bool check(int x) { s.clear(); for (int i = 1; i <= n; i++) { in[i] = vis[i] = dp[i] = 0; g2[i].clear(); if (a[i] <= x) s.insert(i), dp[i] = 1; } for (int i = 1; i <= n; i++) { for (auto j : g[i]) { if (s.find(i) != s.end() && s.find(j) != s.end()) { g2[i].push_back(j); in[j]++; } } } queue<int> q; for (int i = 1; i <= n; i++) { if (s.find(i) != s.end() && !in[i]) q.push(i); } while (!q.empty()) { int j = q.front(); q.pop(); vis[j] = true; if (dp[j] >= k) return true; for (auto u : g2[j]) { if (!vis[u]) { dp[u] = max(dp[u], dp[j] + 1); if (dp[u] >= k) return true; in[u]--; if (!in[u]) q.push(u); } } } for (int i = 1; i <= n; i++) { if (s.find(i) != s.end() && in[i]) return true; } return false; } int main() { #ifdef LOCAL freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout); #endif ios::sync_with_stdio(false), cin.tie(0); cin >> n >> m >> k; for (int i = 1; i <= n; i++) { cin >> a[i]; } for (int i = 1; i <= m; i++) { int u, v; cin >> u >> v; g[u].push_back(v); } ll l = 0, r = 1e9; while (l < r) { ll mid = l + r >> 1; if (check(mid)) r = mid; else l = mid + 1; } // cout << l << endl; if (check(l))cout << l << endl; else cout << -1 << endl; return 0; }

最后

以上就是天真香菇最近收集整理的关于Codeforces Round #791 (Div. 2)(A-D)Codeforces Round #791 (Div. 2)(A-D)的全部内容,更多相关Codeforces内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(84)

评论列表共有 0 条评论

立即
投稿
返回
顶部