CodeTON Round #7 (Div. 1 + Div. 2)

2023-11-29 14:44
文章标签 round div codeton

本文主要是介绍CodeTON Round #7 (Div. 1 + Div. 2),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

A.jagged Swaps

题意:

给出一个包含 n n n个数字的序列,每次可以选择一个同时大于左右两边相邻的数字,将这个数字与它右边的数字交换,问能否在经过若干次操作后使序列变为升序。

分析:

由于交换只能向后进行,且第一个元素无法向后交换(不存在左边的数字),而其他大的数字均可以通过交换到达自己的位置,因此只需要考虑开始时序列的第一个数字是否为1,如果是1,就是"YES",否则,就是"NO"

hint:包含 n n n个数字的序列恰好包含 1 ∼ n 1 \sim n 1n中每一个数字。

代码:

#include <bits/stdc++.h>
using namespace std;int a[15];void solve() {int n;cin >> n;for (int i = 1; i <= n; i++) {cin >> a[i];}if (a[1] != 1) {cout << "NO" << endl;} else {cout << "YES" << endl;}
}int main() {int Case;cin >> Case;while (Case--) {solve();}return 0;
}

B.AB Flipping

题意:

给出一个长度为 n n n且仅包含"AB"两种字符的字符串,每次可以选择一个下标 i i i,当字符串中第 i i i个字符为'A',且第 i + 1 i + 1 i+1个字符为'B',那么可以让第 i i i个字符和第 i + 1 i + 1 i+1个字符交换。

要求每个下标 i i i均只能选择一次,问最多可以进行多少次交换。

分析:

当出现连续的'B'前面有一个'A'时,这段连续区间上的'B'均可以向前交换一次,交换次数为这段连续的'B'的长度,而经过一次交换之后,由于每个下标只能被选择一次,那么仅有第一个'B'还能向前交换,可以认为这段连续的'B'交换完成后就只剩下开头这一个'B'了。使用变量维护还能向前交换的'B'的个数,从后往前遍历模拟即可。

代码:

#include <bits/stdc++.h>
using namespace std;string s;void solve() {int n;cin >> n >> s;int cnt = 0, ans = 0;for (int i = n - 1; i >= 0; i--) {if (s[i] == 'B') {cnt++;} else {ans += cnt;cnt = min(cnt, 1);//如果当前没有遇到过B,就让cnt保持在0}}cout << ans << endl;
}int main() {solve();return 0;
}

C.Matching Arrays

题意:

给出两个包含 n n n个数字的数组 a a a b b b,这两个数组的美丽值为满足 a i > b i a_i > b_i ai>bi的下标 i i i的个数。

题目会给出一个数字 x x x,问能否对 b b b重新排列,使得这两个数组的美丽值等于 x x x

分析:

虽然题目要求只能对 b b b重排,但为了便于处理,两个数组都需要排序,同时为了记录数组 a a a原本的数字位置,需使用结构体存储数据。

贪心:将 a a a中最大的 x x x个元素与 b b b中最小的 x x x个元素按大小次序进行比较,如果这部分元素无法构成 x x x的美丽值,由于 a a a中剩余元素更小, b b b中剩余元素更大,那么无论怎么交换元素,都无法使美丽值增加,此时本题无解。

检查:比较完 a a a中最大的 x x x个元素与 b b b中最小的 x x x个元素后,还需要考虑剩余的元素是否还会产生美丽值,同样采用按大小次序依次比较,如果产生美丽值那么同样表示本题无解。

输出:如果可以构造,那么需要根据记录的 a a a中每个数字排序前的位置将对应的 b b b数组元素输出。

代码:

#include <bits/stdc++.h>
using namespace std;struct Node{int val, id;bool operator < (const Node &o) const {return val < o.val;}
}a[200005], b[200005];int ans[200005];void solve() {int n, x;cin >> n >> x;for (int i = 1; i <= n; i++) {cin >> a[i].val;a[i].id = i;}sort(a + 1, a + 1 + n);for (int i = 1; i <= n; i++) {cin >> b[i].val;b[i].id = i;}sort(b + 1, b + 1 + n);for (int i = 1; i <= x; i++) {if (a[i + n - x].val <= b[i].val) {//a中最大的x个与b中最小的x个对位比较cout << "NO" << endl;return;}ans[a[i + n - x].id] = b[i].val;//将当前b中元素放入对应的a中元素原本所在下标对应的位置上}for (int i = 1; i <= n - x; i++) {if (a[i].val > b[i + x].val) {//剩余的n-x个元素对位比较cout << "NO" << endl;return;}ans[a[i].id] = b[i + x].val;}cout << "YES" << endl;for (int i = 1; i <= n; i++) {cout << ans[i] << ' ';}cout << endl;
}int main() {int Case;cin >> Case;while (Case--) {solve();}return 0;
}

D.Ones and Twos

题意:

给出一个仅包含 1 , 2 1,2 1,2的数组。

q q q个询问,询问分以下两种情况:

  • "1 s",询问数组中能否找出一个子段和为 s s s

  • "2 i v",将数组中第 i i i个数字修改为 v v v

分析:

通过分析样例,可以发现以下规律:如果子段的左右端点数字均为1,那么可以组成任意值在 1 ∼ 1 \sim 1(子段数字之和)以内的数字。

根据以上规律,想要组成尽可能多的数字,那么选择的一定是最左和最右的两个 1 1 1中间的子段(包含端点)。

然后需要根据以下情况进行分类讨论:

  • 数组中存在 1 1 1,这两个 1 1 1之间的子段总和为 s u m sum sum

    • x ≤ s u m x \le sum xsum,则可以组成

    • x > s u m x \gt sum x>sum,分成以下两种情况:

      • x x x s u m sum sum奇偶性相同,为了尽可能使总和最大,一定会选择将选择的子段向左右扩散,且此时左右元素一定均为2,只要整个数组的数字总和可以达到 x x x,那么就能组成 x x x

      • 奇偶性不同时,可以删去子段一侧的 1 1 1,再加上另一侧的 2 2 2,看组成的子段数字总和能否到达 x x x

  • 数组中不存在 1 1 1,那么能组成的只有偶数,且能组成的偶数 x x x的值要在数组中数字总和的范围内。

hint:可以通过 s e t set set对所有 1 1 1所在的位置(下标)进行维护,通过 ∗ ( b e g i n ( ) ) *(begin()) (begin()) ∗ ( − − e n d ( ) ) *(--end()) (end())(end()函数返回的是最后一个元素的下一个迭代器,需要通过前自减得到最后一个元素的迭代器)来获得集合中最小和最大的元素。

代码:

#include <bits/stdc++.h>using namespace std;
int n, q, a[100005], cnt;set<int> S;bool check(int x) {if (S.empty()) {//数组中没有1if (x % 2 == 1) return false;if (n * 2 < x) return false;return true;}int first = *S.begin(), last = *(--S.end());//获得最前和最后的1所在的下标int sum = (last - first + 1) * 2 - S.size();//将区间内所有的数视为2,计算出总和,减去1的数量,就是该子段的数字总和if (sum >= x) return true;//被1包围的子段已经能组成x了if (x % 2 == sum % 2) {int add = n - (last - first + 1);//计算出未被加上的2的数量if (sum + add * 2 >= x) return true;} else {int add = max(n - last, first - 1);//计算左右两边最多有多少个2if (sum - 1 + add * 2 >= x) return true;}return false;
}void solve() {S.clear();cin >> n >> q;for (int i = 1; i <= n; i++) {cin >> a[i];if (a[i] == 1) {S.insert(i);cnt++;}}while (q--) {int op;cin >> op;if (op == 1) {int x;cin >> x;if (check(x)) {cout << "YES" << endl;} else {cout << "NO" << endl;}} else {int i, v;cin >> i >> v;if (a[i] == 1) S.erase(i);a[i] = v;if (a[i] == 1) S.insert(i);}}
}int main() {int Case;cin >> Case;while (Case--) {solve();}return 0;
}

E.Permutation Sorting

更新中…

以下学习交流QQ群,群号: 546235402,大家可以加群一起交流做题思路,分享做题技巧,欢迎大家的加入。

这篇关于CodeTON Round #7 (Div. 1 + Div. 2)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

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

CSS实现DIV三角形

本文内容收集来自网络 #triangle-up {width: 0;height: 0;border-left: 50px solid transparent;border-right: 50px solid transparent;border-bottom: 100px solid red;} #triangle-down {width: 0;height: 0;bor

创建一个大的DIV,里面的包含两个DIV是可以自由移动

创建一个大的DIV,里面的包含两个DIV是可以自由移动 <body>         <div style="position: relative; background:#DDF8CF;line-height: 50px"> <div style="text-align: center; width: 100%;padding-top: 0px;"><h3>定&nbsp;位&nbsp;

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>

CF#271 (Div. 2) D.(dp)

D. Flowers time limit per test 1.5 seconds memory limit per test 256 megabytes input standard input output standard output 题目链接: http://codeforces.com/contest/474/problem/D We s

CF #278 (Div. 2) B.(暴力枚举+推导公式+数学构造)

B. Candy Boxes time limit per test 1 second memory limit per test 256 megabytes input standard input output standard output 题目链接: http://codeforces.com/contest/488/problem/B There

CF#278 (Div. 2) A.(暴力枚举)

A. Giga Tower time limit per test 1 second memory limit per test 256 megabytes input standard input output standard output 题目链接: http://codeforces.com/contest/488/problem/A Giga To