Codeforces Global Round 26 A~E

2024-06-16 15:12
文章标签 codeforces round 26 global

本文主要是介绍Codeforces Global Round 26 A~E,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

A.Strange Splitting(思维)

题意:

将非空数组的范围定义为最大值减去最小值。例如, [ 1 , 4 , 2 ] [1,4,2] [1,4,2]的范围是 4 − 1 = 3 4-1=3 41=3

给你一个长度为 n ≥ 3 n\geq 3 n3的数组 a 1 , a 2 , … , a n a_1,a_2,\ldots,a_n a1,a2,,an保证 a a a被排序

你必须给 a a a中的每个元素涂上红色或蓝色,以便:

  • 红色元素的范围不等于蓝色元素的范围,并且
  • 每种颜色至少有一个元素。

如果不存在这样的着色,则输出 N O NO NO。如果存在多种有效着色,则可以输出其中任何一种。

分析:

如果 a 1 = a n a_1=a_n a1=an,无解。

如果 a 2 = a n a_2=a_n a2=an a 1 , a 2 a_1,a_2 a1,a2涂成红色,否则只把 a 1 a_1 a1涂成红色。

代码:

#include<bits/stdc++.h>using namespace std;
const int N = 1e6 + 10;
int a[N];void solve() {int n;cin >> n;for (int i = 1; i <= n; ++i)cin >> a[i];if (a[1] == a[n]) {cout << "NO" << endl;return;}cout << "YES" << endl;if (a[2] != a[n]) {cout << "R";for (int i = 2; i <= n; ++i) {cout << "B";}cout << endl;return;}cout << "RR";for (int i = 3; i <= n; ++i) {cout << "B";}cout << endl;
}int main() {int t;cin >> t;while (t--)solve();return 0;
}

B.Large Addition(模拟)

题意:

如果一个数位介于 5 5 5 9 9 9之间(含),则该数位为大数。如果一个正整数的所有位数都是大数,那么这个正整数就是大正整数。

给你一个整数 x x x。它可以是两个位数相同的大正整数之和吗?

分析:

由于大于等于 5 5 5小于等于 9 9 9的数不管这么组合,两个数字相加的和一定在 10 − 18 10-18 1018之间,那么可以得到如果给出的数的第一位上不是 1 1 1或者最后一位上是 9 9 9或者或者中间有一位上是 0 0 0,那么就是不存在的,否则就是可行的。

代码:

#include<bits/stdc++.h>typedef long long LL;
using namespace std;void solve() {LL x;cin >> x;bool flag = 1;if (x % 10 == 9)flag = 0;x /= 10;while (x) {int y = x % 10;if ((y + 9) % 10 == 9)flag = 0;if (x < 10 && y > 1)flag = 0;x /= 10;}if (flag)cout << "YES" << endl;elsecout << "NO" << endl;
}int main() {int t;cin >> t;while (t--)solve();return 0;
}

C1.Magnitude (Easy Version)(贪心)

题意:

两个版本的问题是不同的。

给你一个长度为 n n n的数组 a a a。从 c = 0 c=0 c=0开始。然后,对于从 1 1 1 n n n的每一个 i i i(按递增顺序)做下面的操作之一

  • 选项 1 1 1: 设置 c c c c + a i c+a_i c+ai
  • 选项 2 2 2: 设置 c c c ∣ c + a i ∣ |c+a_i| c+ai ∣ x ∣ |x| x x x x的绝对值。

设上述步骤后 c c c的最大终值等于 k k k。求出 k k k

分析:

发现要么一直不用 2 2 2操作,要么在答案取到最小值的时候使用一遍 2 2 2操作让其变为相对大一些的值。显然使用多遍 2 2 2操作是不优的。然后还能发现若存在一个位置 P P P使得前缀和小于 0 0 0,那么这个地方实验 2 2 2操作较优。因此若不存在一个前缀和的值小于 0 0 0那么就不应该使用 2 2 2操作。否则一定在任意一个值最小的位置使用一次 2 2 2操作即可。

代码:

#include<bits/stdc++.h>typedef long long LL;
using namespace std;
const int N = 1e6 + 10;
LL a[N], pre[N];void solve() {LL n, id = -1;cin >> n;for (LL i = 1; i <= n; i++) {cin >> a[i];pre[i] = pre[i - 1] + a[i];}LL mi = 0;for (LL i = n; i; i--) {if (pre[i] < mi) {mi = pre[i];id = i;}}if (id == -1)cout << pre[n] << endl;else {LL s = 0;for (LL i = 1; i <= n; i++) {if (i <= id)s -= a[i];elses += a[i];}cout << s << endl;}
}int main() {int t;cin >> t;while (t--)solve();return 0;
}

C2.Magnitude (Hard Version)(贪心)

题意:

两个版本的问题是不同的。

给你一个长度为 n n n的数组 a a a。从 c = 0 c=0 c=0开始。然后,对于从 1 1 1 n n n的每个 i i i(按递增顺序),做以下操作之一

  • 选项 1 1 1:设置 c c c c + a i c+a_i c+ai
  • 选项 2 2 2:设置 c c c ∣ c + a i ∣ |c+a_i| c+ai ∣ x ∣ |x| x x x x的绝对值。

假设经过上述程序后, c c c的最大终值等于 k k k。求得出 c = k c=k c=k的唯一程序的个数。如果在任意索引 i i i处,一个程序选择了选项 1 1 1,而另一个程序选择了选项 2 2 2,即使 c c c的值在该轮之后对两个程序都相等,那么这两个程序也是不同的。

由于答案可能很大,输出对 998244353 998244353 998244353取模的结果。

分析:

每一步结束之后,若当前的前缀和取到了全部前缀和的最小值,则这一步对答案造成了 2 n − i + r 2^{n-i+r} 2ni+r贡献,其中 r r r是在这一步操作中前缀和不小于 0 0 0的位置的数量。若全部操作中没有任何一个前缀和小于 0 0 0则答案为 2 n 2^n 2n

不存在任何一个前缀和使得这个前缀和不大于 0 0 0。此时对于任意一个位置 1 1 1操作和 2 2 2操作没有任何本质区别。任意一步都可以在 1 1 1操作和 2 2 2操作中任选一个操作执行。

存在一个前缀和使得这个前缀和不大于 0 0 0。因为执行完这一步之后后面不论怎么走答案都不会偏离最大值(参见 C 1 C1 C1的结论),所以说后面的任意一步都可以在 1 1 1操作和 2 2 2操作中任选,即 2 n − i 2^{n-i} 2ni种不同选择;若前面有前缀和大于等于 0 0 0的那么 1 1 1操作和 2 2 2操作没有本质的区别,若有 r r r个满足这样条件的则有 2 r 2^r 2r种不同选择。根据乘法原理可知对答案的贡献为 2 n − i + r 2^{n-i+r} 2ni+r。其中 r r r可以在枚举的时候扫一遍得出答案。

代码:

#include<bits/stdc++.h>typedef long long LL;
using namespace std;
const int N = 1e6 + 10;
const int MOD = 998244353;
LL a[N], pre[N], bin[N];void solve() {int n;cin >> n;for (int i = 1; i <= n; i++) {cin >> a[i];pre[i] = pre[i - 1] + a[i];}LL mi = 0, r = 0;for (int i = 1; i <= n; i++)mi = min(mi, pre[i]);if (mi == 0)cout << bin[n] << endl;else {int ans = 0;for (int i = 1; i <= n; i++) {if (pre[i] >= 0)r++;if (pre[i] == mi)ans = (ans + bin[n - i + r]) % MOD;}cout << ans << endl;}
}int main() {int t;cin >> t;bin[0] = 1;for (int i = 1; i < N; i++)bin[i] = bin[i - 1] * 2 % MOD;while (t--)solve();return 0;
}

D.“a” String Problem(数学)

题意:

给你一个由小写拉丁字符组成的字符串 s s s。请计算非空字符串 t ≠ t\neq t=" a \texttt{a} a"的个数。使得可以将 s s s分割为满足以下条件的一些子字符串:

  • 每个子串要么等于 t t t要么等于" a \texttt{a} a",并且
  • 至少有一个子串等于 t t t

† ^{\dagger} 字符串 s s s的分区是由一些 k k k字符串 t 1 , t 2 , … , t k t_1,t_2,\ldots,t_k t1,t2,,tk(称为子串)组成的有序序列,使得 t 1 + t 2 + … + t k = s t_1+t_2+\ldots+t_k=s t1+t2++tk=s,其中 + + +表示连接操作。

分析:

s s s长度为 n n n。特判全为 a a a的情况,共 n − 1 n−1 n1种方案。

s s s中非 a a a字符的数量为 m m m

如果 t t t中有 k k k个非 a a a字符,把 t t t掐头去尾忽略前后的 a a a后,原串里一定恰好存在 m k \frac{m}{k} km t ′ t′ t,且 k ∣ m k∣m km

枚举 k k k。记录第 i i i个非 a a a字符的位置为 p i p_i pi(从 0 0 0开始),如果 s p i ≠ s p i − k s_{p_i} \neq s_{p_i−k} spi=spik或不在分割处的 p i − p i − 1 ≠ p i − k − p i − k − 1 p_i−p_{i−1}\neq p_{i−k}−p_{i−k−1} pipi1=pikpik1 t ′ t′ t不合法。

t ′ t′ t还原为 t t t,枚举左边有的 a a a个数 l ∈ [ 0 , p 0 ] l∈[0,p_0] l[0,p0]

x x x为分割处的最小间隔 m i n ( p i − p i − 1 ) min(p_i−p_{i−1}) min(pipi1) k ∣ i k∣i ki,则右边的 a a a个数 r ∈ [ 0 , m i n ( x − l , n − p m − 1 − 1 ) ] r∈[0,min(x−l,n−p_{m−1}-1)] r[0,min(xl,npm11)]

代码:

#include<bits/stdc++.h>typedef long long LL;
using namespace std;
const int MOD = 998244353;void solve() {string s;cin >> s;int n = s.length();if (count(s.begin(), s.end(), 'a') == n) {cout << n - 1 << endl;return;}vector<int> a;for (int i = 0; i < n; ++i) {if (s[i] != 'a') {a.emplace_back(i);}}int m = a.size();LL ans = 0;for (int i = 1; i <= m; ++i) {if (m % i) {continue;}int ok = 1;for (int j = i; j < m; ++j) {int o = j % i;if (s[a[j]] != s[a[o]] || (o && a[o] - a[o - 1] != a[j] - a[j - 1])) {ok = 0;break;}}if (ok) {int mi = n;for (int j = i; j < m; j += i) {mi = min(mi, a[j] - a[j - 1] - 1);}int r = n - a.back() - 1;for (int l = 0; l <= a[0]; ++l) {ans += max(0, min(r + 1, mi - l + 1));}}}cout << ans << endl;
}int main() {int t;cin >> t;while (t--)solve();return 0;
}

E.Shuffle(树形DP)

题意:

两只饥饿的小熊猫奥斯卡和卢拉有一棵有 n n n个节点的树 T T T。它们愿意在整棵树 T T T精确地执行一次下面的洗牌程序。通过这个洗牌过程,他们将从旧树的节点中创建一棵新树。

  1. 从原始树 T T T中选择任意一个节点 V V V。创建一棵以 V V V为根的新树 T 2 T_2 T2
  2. T T T中移除 V V V,这样原树就会分裂成一个或多个子树(如果 V V V T T T中的唯一节点,则子树数量为零)。
  3. 用同样的方法对每棵子树进行洗牌(同样选择任意节点作为根节点),然后将所有洗牌后子树的根节点连接回 V V V以完成 T 2 T_2 T2的构建。

这样,奥斯卡和卢拉就得到了一棵新树 T 2 T_2 T2。它们只能吃树叶,而且非常饥饿,因此请找出在所有树中,只需一次洗牌就能生成的树叶的最大数量。

请注意,树叶是阶数为 1 1 1的所有节点。因此,如果树根只有一个子节点,那么它就可以被视为树叶。

分析:

把一个点的父亲儿子都加到 T 2 T_2 T2后,这个点就是叶子,且与之直接相连的点都不是叶子。(所有相邻点都是这个点的祖先)。

所有的叶子构成一个独立集,我们找去除根后最大的。

枚举每个节点作为初始的根,换根进行 d p dp dp。如果根本身就是叶子还要在加一。

具体来说,第一次扫描以 1 1 1为根求出 f x , 1 / 0 f_{x,1/0} fx,1/0表示以 x x x为根的子树中 x x x选/不选的最大独立集:
{ f x , 0 = ∑ y ∈ g x max ⁡ ( f y , 0 , f y , 1 ) f x , 1 = ∑ y ∈ g x f y , 0 \begin{cases}f_{x,0}=\sum_{y\in g_x}\max(f_{y,0},f_{y,1})\\f_{x,1}=\sum_{y\in g_x}f_{y,0}\end{cases} {fx,0=ygxmax(fy,0,fy,1)fx,1=ygxfy,0

第二次扫描求出 h x , 1 / 0 h_{x,1/0} hx,1/0表示选/不选 x x x的最大独立集,
h 1 , 0 / 1 = f 1 , 0 / 1 h_{1,0/1}=f_{1,0/1} h1,0/1=f1,0/1 { h x , 0 = max ⁡ ( h f a , 1 , f x , 0 + ( h f a , 0 − max ⁡ ( f x , 1 , f x , 0 ) ) ) h x , 1 = f x , 1 + ( h f a , 0 − max ⁡ ( f x , 1 , f x , 0 ) ) \begin{cases}h_{x,0}=\max(h_{fa,1},f_{x,0}+(h_{fa,0}-\max(f_{x,1},f_{x,0})))\\h_{x,1}=f_{x,1}+(h_{fa,0}-\max(f_{x,1},f_{x,0}))\end{cases} {hx,0=max(hfa,1,fx,0+(hfa,0max(fx,1,fx,0)))hx,1=fx,1+(hfa,0max(fx,1,fx,0))

h x , 0 + [ x is leaf ] h_{x,0}+[x \texttt{ is leaf}] hx,0+[x is leaf]更新答案。

代码:

#include<bits/stdc++.h>using namespace std;
const int MOD = 998244353;void solve() {int n;cin >> n;vector<vector<int>> g(n + 1);for (int i = 1; i < n; ++i) {int x, y;cin >> x >> y;g[x].emplace_back(y);g[y].emplace_back(x);}vector<array<int, 2>> f(n + 1, {0, 0});auto dfs = [&](auto &&dfs, int x, int fa) -> void {f[x][0] = 0;f[x][1] = 1;for (int y: g[x]) {if (y != fa) {dfs(dfs, y, x);f[x][0] += max(f[y][0], f[y][1]);f[x][1] += f[y][0];}}};dfs(dfs, 1, 0);vector<array<int, 2>> h(n + 1);h[1][0] = f[1][0];h[1][1] = f[1][1];int ans = h[1][0] + (g[1].size() == 1);auto dfs2 = [&](auto &&dfs2, int x, int fa) -> void {int tmp = h[fa][0] - max(f[x][0], f[x][1]);h[x][1] = f[x][1] + tmp;h[x][0] = max(h[fa][1], f[x][0] + tmp);tmp = h[x][0] + (g[x].size() == 1);ans = max(ans, tmp);for (int y: g[x]) {if (y != fa) {dfs2(dfs2, y, x);}}};for (int y: g[1]) {dfs2(dfs2, y, 1);}cout << ans << endl;
}int main() {int t;cin >> t;while (t--)solve();return 0;
}

赛后交流

在比赛结束后,会在交流群中给出比赛题解,同学们可以在赛后查看题解进行补题。

群号: 704572101,赛后大家可以一起交流做题思路,分享做题技巧,欢迎大家的加入。

这篇关于Codeforces Global Round 26 A~E的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1066790

相关文章

Linux下MySQL8.0.26安装教程

《Linux下MySQL8.0.26安装教程》文章详细介绍了如何在Linux系统上安装和配置MySQL,包括下载、解压、安装依赖、启动服务、获取默认密码、设置密码、支持远程登录以及创建表,感兴趣的朋友... 目录1.找到官网下载位置1.访问mysql存档2.下载社区版3.百度网盘中2.linux安装配置1.

Codeforces Round #240 (Div. 2) E分治算法探究1

Codeforces Round #240 (Div. 2) E  http://codeforces.com/contest/415/problem/E 2^n个数,每次操作将其分成2^q份,对于每一份内部的数进行翻转(逆序),每次操作完后输出操作后新序列的逆序对数。 图一:  划分子问题。 图二: 分而治之,=>  合并 。 图三: 回溯:

Codeforces Round #261 (Div. 2)小记

A  XX注意最后输出满足条件,我也不知道为什么写的这么长。 #define X first#define Y secondvector<pair<int , int> > a ;int can(pair<int , int> c){return -1000 <= c.X && c.X <= 1000&& -1000 <= c.Y && c.Y <= 1000 ;}int m

Codeforces Beta Round #47 C凸包 (最终写法)

题意慢慢看。 typedef long long LL ;int cmp(double x){if(fabs(x) < 1e-8) return 0 ;return x > 0 ? 1 : -1 ;}struct point{double x , y ;point(){}point(double _x , double _y):x(_x) , y(_y){}point op

Codeforces Round #113 (Div. 2) B 判断多边形是否在凸包内

题目点击打开链接 凸多边形A, 多边形B, 判断B是否严格在A内。  注意AB有重点 。  将A,B上的点合在一起求凸包,如果凸包上的点是B的某个点,则B肯定不在A内。 或者说B上的某点在凸包的边上则也说明B不严格在A里面。 这个处理有个巧妙的方法,只需在求凸包的时候, <=  改成< 也就是说凸包一条边上的所有点都重复点都记录在凸包里面了。 另外不能去重点。 int

Codeforces 482B 线段树

求是否存在这样的n个数; m次操作,每次操作就是三个数 l ,r,val          a[l] & a[l+1] &......&a[r] = val 就是区间l---r上的与的值为val 。 也就是意味着区间[L , R] 每个数要执行 | val 操作  最后判断  a[l] & a[l+1] &......&a[r] 是否= val import ja

Codeforces Round 971 (Div. 4) (A~G1)

A、B题太简单,不做解释 C 对于 x y 两个方向,每一个方向至少需要 x / k 向上取整的步数,取最大值。 由于 x 方向先移动,假如 x 方向需要的步数多于 y 方向的步数,那么最后 y 方向的那一步就不需要了,答案减 1 代码 #include <iostream>#include <algorithm>#include <vector>#include <string>

Codeforces#295(Div.2)A、B(模拟+BFS)

解题报告链接:点击打开链接 C. 题目链接:点击打开链接 解题思路: 对于给定的字符串,取出现次数最多的字母(可以同时有多个)。由这些字母组成长度为n的字符串,求有多少种组合。最后用数学知识即可。 完整代码: #include <algorithm>#include <iostream>#include <cstring>#include <climits>

MemSQL Start[c]UP 2.0 - Round 1A(构造)

题目链接:http://codeforces.com/problemset/problem/452/A 解题思路: 打个表暴力查找匹配。 完整代码: #include <algorithm>#include <iostream>#include <cstring>#include <complex>#include <cstdio>#include <strin

Codeforces Round #281 (Div. 2)A(构造+暴力模拟)

题目链接:http://codeforces.com/problemset/problem/493/A 解题思路: 暴力的判断,分三种情况去判断即可。注意如果之前已经被罚下场后,那么在后面的罚下情况不应该算在输出结果内。 完整代码: #include <algorithm>#include <iostream>#include <cstring>#include <co