Codeforces Round 784 (Div. 4)

Codeforces Round 784 (Div. 4) 题解

Codeforces Round 784 (Div. 4) 题解

A. Division?

题目大意:

Codeforces根据用户等级将其划分为 444 类:

-第1部分: 1900≤rating1900 \leq \mathrm{rating}1900rating
-部分2: 1600≤rating≤18991600 \leq \mathrm{rating} \leq 18991600rating1899
-对于分区3: 1400≤rating≤15991400 \leq \mathrm{rating} \leq 15991400rating1599
-分区4: rating≤1399\mathrm{rating} \leq 1399rating1399

给定一个 rating\mathrm{rating}rating ,打印 rating\mathrm{rating}rating 属于哪个组别。

样例输入

7
-789
1299
1300
1399
1400
1679
2300

样例输出

Division 4
Division 4
Division 4
Division 4
Division 3
Division 2
Division 1

思路

多个if判断即可

代码

#include <bits/stdc++.h>
using namespace std;

void solve() {
	int n;
	cin >> n;
	if(n >= 1900) cout << "Division 1" << endl;
	else if(n >= 1600) cout << "Division 2" << endl;
	else if(n >= 1400) cout << "Division 3" << endl;
	else cout << "Division 4" << endl;	
	
}

signed main() {
	
	int t = 1;
	cin >> t;
	
	for(int i = 1; i <= t; i++)
		solve();
	
	return 0;
}

B. Triple

题目大意:

给定一个包含 nnn 元素的数组 aaa ,打印任何出现至少三次的值,如果没有出现则打印-1。

样例输入

7
1
1
3
2 2 2
7
2 2 3 3 4 2 2
8
1 4 3 4 3 2 4 1
9
1 1 1 2 2 2 3 3 3
5
1 5 2 4 3
4
4 4 4 4

样例输出

-1
2
2
4
3
-1
4

思路

map统计出现次数,输出超过三次的即可

代码

#include <bits/stdc++.h>
using namespace std;

void solve() {
	int n; cin >> n;
	map<int, int> mp;
	for(int i = 0; i < n; i++) {
		int k; cin >> k;
		mp[k]++;
	}
	int res = 0;
	for(auto &[a, b] : mp)
		if(b >= 3) {
			res++;
			cout << a << " ";
			break;
		}
	if(res == 0) cout << -1;
	cout << endl;	
}

signed main() {
	
	int t = 1;
	cin >> t;
	
	for(int i = 1; i <= t; i++)
		solve();
	
	return 0;
}

C. Odd/Even Increments

题目大意:

给定一个包含 nnn 个正整数的数组 a=[a1,a2,…,an]a=[a_1,a_2,\dots,a_n]a=[a1,a2,,an] ,你可以对它进行两种类型的操作:

  1. 111 添加到每一个奇数索引的元素。也就是说,将数组修改为: a1:=a1+1,a3:=a3+1,a5:=a5+1,…a_1 := a_1 +1, a_3 := a_3 + 1, a_5 := a_5+1, \dotsa1:=a1+1,a3:=a3+1,a5:=a5+1,

  2. 111 添加到每个具有偶数索引的元素。换句话说,将数组修改为: a2:=a2+1,a4:=a4+1,a6:=a6+1,…a_2 := a_2 +1, a_4 := a_4 + 1, a_6 := a_6+1, \dotsa2:=a2+1,a4:=a4+1,a6:=a6+1,

确定在任意数量的操作之后,是否有可能使最终数组只包含偶数或只包含奇数。

换句话说,确定是否可以在任意次数的操作之后使数组的所有元素具有相同的奇偶校验。

注意,这两种类型的操作可以执行任意次数(甚至不执行)。不同类型的操作可以执行不同的次数。

样例输入

4
3
1 2 1
4
2 2 2 3
4
2 2 2 2
5
1000 1 1000 1 1000

样例输出

YES
NO
YES
YES

思路

偶数位与奇数位的操作都是互相独立的,单独判断。

不难发现,只有当偶数位的所有数字奇偶性一样并且奇数位的所有数字奇偶性一样最后的结果才能一样。

分别统计奇偶位上奇数的数量即可。

代码

#include <bits/stdc++.h>
using namespace std;

void solve() {
	int n; cin >> n;
	int a[2] = {0};
	for(int i = 1; i <= n; i++) {
		int k; cin >> k;
		a[i % 2] += k % 2;
	}
	if(a[0] != 0 and a[0] != n / 2) {
		cout << "NO\n";
		return ;
	}
	if(a[1] != 0 and a[1] != n / 2 + n % 2) {
		cout << "NO\n";
		return ;
	}
	cout << "YES\n";
}

signed main() {
	
	int t = 1;
	cin >> t;
	
	for(int i = 1; i <= t; i++)
		solve();
	
	return 0;
}

D. Colorful Stamp

题目大意:

给出了一行 nnn 单元格,最初都是白色的。使用图章,您可以在任意两个相邻的单元格上图章,使一个单元格变成红色,另一个单元格变成蓝色。邮票可以旋转,即它可以以两种方式使用:作为 BR\color{blue}{\texttt{B}}\color{red}{\texttt{R}}BR 和作为 RB\color{red}{\texttt{R}}\color{blue}{\texttt{B}}RB

在使用期间,戳记必须完全适合给定的 nnn 单元格(它不能部分地在单元格之外)。戳可以多次应用于同一单元格。每次使用图章都会对图章下的两个单元格重新上色。

例如,制作图片 BRBBW\color{blue}{\texttt{B}}\color{red}{\texttt{R}}\color{blue}{\texttt{B}}\color{blue}{\texttt{B}}\texttt{W}BRBBW 的一个可能的邮票序列可以是 WWWWW→WWRB‾W→BR‾RBW→BRB‾BW\texttt{WWWWW} \to \texttt{WW}\color{brown}{\underline{\color{red}{\texttt{R}}\color{blue}{\texttt{B}}}}\texttt{W} \to \color{brown}{\underline{\color{blue}{\texttt{B}}\color{red}{\texttt{R}}}}\color{red}{\texttt{R}}\color{blue}{\texttt{B}}\texttt{W} \to \color{blue}{\texttt{B}}\color{brown}{\underline{\color{red}{\texttt{R}}\color{blue}{\texttt{B}}}}\color{blue}{\texttt{B}}\texttt{W}WWWWWWWRBWBRRBWBRBBW 。这里 W\texttt{W}WR\color{red}{\texttt{R}}RB\color{blue}{\texttt{B}}B 分别表示白色、红色或蓝色单元格,使用戳记的单元格用下划线标记。

给定最终的图片,是否有可能使用零次或多次戳记来制作它?

样例输入

12
5
BRBBW
1
B
2
WB
2
RW
3
BRB
3
RBB
7
WWWWWWW
9
RBWBWRRBW
10
BRBRBRBRRB
12
BBBRWWRRRWBR
10
BRBRBRBRBW
5
RBWBW

样例输出

YES
NO
NO
NO
YES
YES
YES
NO
YES
NO
YES
NO

思路

先按照白色位置W分割,然后单独判断每一小段。

对于每一小段,应该保证长度>=2>=2>=2的同时包含RB两种颜色,否则就是不可行的方案。

代码

n = int(input())

for i in range(n):
	a = int(input())
	s = input().split("W")
	mk = 1
	for j in s:
		if j == '':
			continue
		if len(j) == 1:
			mk = 0
		x, y = 0, 0
		for k in j:
			if k == 'R':
				x += 1
			else:
				y += 1
		if x == 0 or y == 0:
			mk = 0	
	
	if mk == 0:
		print("NO")
	else:
		print("YES")

E. 2-Letter Strings

题目大意:

给你nnn个只包含两个小写字母的字符串,问满足i<ji < ji<j同时只有一个字母相同的索引 (i,j)(i,j)(i,j) 对的个数。

样例输入

4
6
ab
cb
db
aa
cc
ef
7
aa
bb
cc
ac
ca
bb
aa
4
kk
kk
ab
ab
5
jf
jf
jk
jk
jk

样例输出

5
6
0
6

样例解释

对于第一个测试用例,在一个位置上不同的配对是**(“ab”, “cb”), (“ab”, “db”), (“ab”, “aa”), (“cb”, “db”)** 和 (“cb”, “cc”)

在第二个测试案例中,有一个位置上不同的配对是**(“aa”, “ac”), (“aa”, “ca”), (“cc”, “ac”), (“cc”, “ca”), (“ac”, “aa”)** 和 (“ca”, “aa”)

对于第三个测试用例,没有满足条件的配对。

思路

由于字符串长度为222且只包含小写字母,直接创建数组f[i][j]f[i][j]f[i][j]暴力统计所有字符串出现次数。

然后循环分别找第一个位置不同与第二个位置不同的数量加起来。

代码

#include <bits/stdc++.h>
#define int long long
using namespace std;

void solve() {
	int n; cin >> n;
	int f[30][30] = {0};
	int res = 0;
	for(int i = 1; i <= n; i++) {
		string s; cin >> s;
		for(int j = 0; j <= 25; j++) {
			if(j != s[1] - 'a') {
				res += f[s[0] - 'a'][j];
			}
			if(j != s[0] - 'a') {
				res += f[j][s[1] - 'a'];
			}
		}
		f[s[0] - 'a'][s[1] - 'a']++;
	}
	cout << res << endl;
}

signed main() {
	
	int t = 1;
	cin >> t;
	
	for(int i = 1; i <= t; i++)
		solve();
	
	return 0;
}

F. Eating Candies

题目大意:

一张桌子上从左到右放着 nnn 粒糖果。这些糖果从左到右依次编号。 iii (颗)糖果的重量为 wiw_iwi 。爱丽丝和鲍勃吃糖。

爱丽丝可以从左边开始吃任意数量的糖果(她不能跳着吃,要连续吃)。

鲍勃可以从右边吃任意数量的糖果(他不能跳着吃,要连续吃)。

当然,如果爱丽丝吃了一颗糖,鲍勃就不能吃(反之亦然)。

他们希望公平。他们的目标是吃掉相同总重量的糖果。他们总共能吃多少颗糖果?

样例输入

4
3
10 20 10
6
2 1 4 2 4 1
5
1 2 4 8 16
9
7 3 20 5 15 1 11 8 10

样例输出

2
6
0
7

思路

先用map统计出所有的前缀和与后缀和的出现次数,如果一个数出现了两次,那么说明是可行的方案,我们找到最大的这个数即可。

具体看代码注释。

代码

#include <bits/stdc++.h>
#define int long long
using namespace std;

void solve() {
	int n; cin >> n;
	vector<int> l(n), r(n);
	for(auto &i : l) cin >> i;
    // mp 统计前缀和与后缀出现次数
    // L, R 分别统计前后缀和出现位置
	map<int, int> mp, L, R;
	r[n - 1] = l[n - 1];
	mp[r[n - 1]]++, mp[l[0]]++;
	R[r[n - 1]] = n - 1, L[l[0]] = 0;
	for(int i = n - 2; i >= 0; i--) {
		r[i] = r[i + 1] + l[i];
		mp[r[i]]++;
		R[r[i]] = i;
	}
	for(int i = 1; i < n; i++) {
		l[i] += l[i - 1];
		mp[l[i]]++;
		L[l[i]] = i;
	}
	int res = 0;
	for(auto &[k, v] : mp) {
        // 如果一个数出现次数大于 2 则说明前后缀都有出现
        // k * 2 <= r[0] 则保证前后缀没有重叠区间
		if(v >= 2 and k * 2 <= r[0]) res = max(res, k);
	}
	// cout << res << endl;
	if(res == 0) cout << "0\n";
	else cout << L[res] + 1 + n - R[res] << endl;
}

signed main() {
	
	int t = 1;
	cin >> t;
	
	for(int i = 1; i <= t; i++)
		solve();
	
	return 0;
}

G. Fall Down

题目大意

网格中有 nnn 行和 mmm 列,以及三种类型的单元格:

  • 空单元格,用.表示。
  • 石头,用*表示。
  • 障碍物,用小写拉丁字母o表示。

所有石子都会往下掉,直到碰到地板(最下面一行)、障碍物或其他已经无法移动的石子。(换句话说,所有的石子只要还能往下掉,就会一直往下掉)。

模拟这一过程。得到的网格是什么样的?

样例输入

3
6 10
.*.*....*.
.*.......*
...o....o.
.*.*....*.
..........
.o......o*
2 9
...***ooo
.*o.*o.*o
5 5
*****
*....
*****
....*
*****

样例输出

..........
...*....*.
.*.o....o.
.*........
.*......**
.o.*....o*

....**ooo
.*o**o.*o

.....
*...*
*****
*****
*****

思路

每一列单独从下往上模拟即可。

  • 先找空单元格
  • 再往上找石头
    • 如果遇到障碍物,就回到第一步
    • 如果遇到石头,就跟前面找的空单元格交换位置,再回到第一步

代码

#include <bits/stdc++.h>
#define int long long
using namespace std;

void solve() {
	int n, m;
	cin >> n >> m;
	vector<string> v(n);
	for(auto &i : v) cin >> i;

	for(int j = 0; j < m; j++) {
		int x = n - 1, y = j;
		while(x >= 0) {
			while(x >= 0 and v[x][y] != '.') x--;
			// 没找到空单元格,退出循环
			if(x < 0) break;
			// 记录空单元格位置
			int bef = x;
			// 再往上找非空单元格
			while(x >= 0 and v[x][y] == '.') x--;
			// 没找到其他单元格,退出循环
			if(x < 0) break;
			// 如果找到石头,就交换位置
			if(v[x][y] == '*') {
				swap(v[bef][y], v[x][y]);
				// x 设置为上一个位置继续找
				x = bef - 1;
			}
		}
	}

	
	for(auto &i : v) cout << i << endl;
	cout << endl;
}

signed main() {
	
	int t = 1;
	cin >> t;
	
	for(int i = 1; i <= t; i++)
		solve();
	
	return 0;
}

H. Maximal AND

题目大意:

AND\mathsf{AND}AND 表示按位与运算, OR\mathsf{OR}OR 表示按位或运算。

给你一个长度为 nnn 的数组 aaa 和一个非负整数 kkk 。你最多可以对数组进行以下类型的 kkk 操作:

  • 选择索引 iii ( 1≤i≤n1 \leq i \leq n1in ),并将 aia_iai 替换为 ai OR 2ja_i\ \mathsf{OR}\ 2^jai OR 2j 其中 jjj000303030 之间的任意整数。包含。换句话说,在操作中,您可以选择索引 iii ( 1≤i≤n1 \leq i \leq n1in ),并将 aia_iaijjj /th 位设置为 111 ( 0≤j≤300 \leq j \leq 300j30 )。

输出 a1a_1a1 AND\mathsf{AND}AND a2a_2a2 AND\mathsf{AND}AND …\dots AND\mathsf{AND}AND ana_nan 的最大可能值,最多执行 kkk 次操作。

样例输入

4
3 2
2 1 1
7 0
4 6 6 28 6 6 12
1 30
0
4 4
3 1 3 1

样例输出

2
4
2147483646
1073741825

思路

最后要的结果是所有数字AND\mathsf{AND}AND的结果,ai<231a_i < 2^{31}ai<231,那么结果只要判断二进制的前三十一位。

要想结果二进制的第iii位为111,那么要保证所有数字的第iii位都为111

我们先统计所有数字二进制第iii位等于111的次数,再从高到低把每一位设置成111即可。

代码

#include <bits/stdc++.h>
#define int long long
using namespace std;

void solve() {
	int n, m;
	cin >> n >> m;
    // 统计第 i 位为 1 的数量
	int f[31] = {0};
	for(int i = 1; i <= n; i++) {
		int k; cin >> k;
		for(int j = 0; j <= 30; j++)
			if((k & (1 << j)) > 0)
				f[j]++;
	}
	long long ans = 0;
    // 从高到低把每一位设置成 1
	for(int i = 30; i >= 0; i--) {
        // 如果剩下的操作次数足够把第 i 位设置成 1
		if(n - f[i] <= m) {
            // 那么答案的第 i 位结果一定为 1
			ans |= (1ll << i);
            // 减去操作次数
			m -= n - f[i];
		}
	}
	cout << ans << endl;
}

signed main() {
	
	int t = 1;
	cin >> t;
	
	for(int i = 1; i <= t; i++)
		solve();
	
	return 0;
}
### Codeforces Round 927 Div. 3 比赛详情 Codeforces是一个面向全球程序员的比赛平台,定期举办不同级别的编程竞赛。Div. 3系列比赛专为评级较低的选手设计,旨在提供更简单的问题让新手能够参与并提升技能[^1]。 #### 参赛规则概述 这类赛事通常允许单人参加,在规定时间内解决尽可能多的问题来获得分数。评分机制基于解决问题的速度以及提交答案的成功率。比赛中可能会有预测试案例用于即时反馈,而最终得分取决于系统测试的结果。此外,还存在反作弊措施以确保公平竞争环境。 ### 题目解析:Moving Platforms (G) 在这道题中,给定一系列移动平台的位置和速度向量,询问某时刻这些平台是否会形成一条连续路径使得可以从最左端到达最右端。此问题涉及到几何学中的线段交集判断和平面直角坐标系内的相对运动分析。 为了处理这个问题,可以采用如下方法: - **输入数据结构化**:读取所有平台的数据,并将其存储在一个合适的数据结构里以便后续操作。 - **时间轴离散化**:考虑到浮点数精度误差可能导致计算错误,应该把整个过程划分成若干个小的时间间隔来进行模拟仿真。 - **碰撞检测算法实现**:编写函数用来判定任意两个矩形之间是否存在重叠区域;当发现新的连接关系时更新可达性矩阵。 - **连通分量查找技术应用**:利用图论知识快速求解当前状态下哪些节点属于同一个集合内——即能否通过其他成员间接相连。 最后输出结果前记得考虑边界条件! ```cpp // 假设已经定义好了必要的类和辅助功能... bool canReachEnd(vector<Platform>& platforms, double endTime){ // 初始化工作... for(double currentTime = startTime; currentTime <= endTime ;currentTime += deltaT){ updatePositions(platforms, currentTime); buildAdjacencyMatrix(platforms); if(isConnected(startNode,endNode)){ return true; } } return false; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值