A. 三层甲板
https://codeforces.com/contest/2104/problem/A
每次测试时限:2 秒
每次测试的内存限制:512 兆字节
输入:标准输入
输出:标准输出
Monocarp 在桌子上一排摆放了三副扑克牌。第一副牌是 a a a,第二副牌是 b b b,第三副牌是 c c c,条件是 a < b < c a < b < c a<b<c。
Monocarp 想要从第三副牌中抽取一些牌(至少一张,但不多于 c c c),并将它们分配到前两副牌中,这样抽取的每一张牌最终都会出现在第一副牌或第二副牌中。从第三副牌中抽取的所有牌都有可能放入同一副牌中。
你的任务是确定 Monocarp 是否能通过所述操作使三副牌的张数相等。
输入
第一行包含一个整数 t t t( 1 ≤ t ≤ 1 0 4 1 \le t \le 10^4 1≤t≤104)— 测试用例数。
每个测试用例的唯一一行包含三个整数 a a a, b b b 和 c c c( 1 ≤ a , b , c ≤ 1 0 8 1 \le a, b, c \le 10^8 1≤a,b,c≤108)— 分别是第一副牌、第二副牌和第三副牌的张数。
输入的额外限制: a < b < c a < b < c a<b<c。
输出
对于每个测试用例,如果 Monocarp 可以通过所述操作使三副牌的牌数相等,则输出 “YES”(不带引号)。否则,输出 “NO”(不带引号)。
解题思路:判断牌数是否相等
-
判断总牌数是否能被3整除:
如果 a + b + c a + b + c a+b+c 不能被3整除,那么无法使三副牌的张数相等,直接输出“NO”。 -
计算目标牌数:
如果总牌数能被3整除,计算目标牌数 a v g = a + b + c 3 avg = \frac{a + b + c}{3} avg=3a+b+c。 -
判断是否满足条件:
计算 a − a v g a - avg a−avg、 b − a v g b - avg b−avg 和 c − a v g c - avg c−avg。
如果 c < 0 c < 0 c<0 或 a > 0 a > 0 a>0 或 b > 0 b > 0 b>0,说明无法通过移动牌使三副牌的张数相等,输出“NO”。
否则,输出“YES”。
AC Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
void solve() {
int a,b,c;
cin >> a >> b >> c;
if((a+b+c)%3 != 0) {
cout << "NO" << endl;
return;
}
int avg = (a + b + c) / 3;
a-= avg;
b-= avg;
c-= avg;
if(c<0||a>0||b>0) {
cout << "NO" << endl;
return;
}
if(a+b+c == 0 && a<= c && b <= 0) {
cout << "YES" << endl;
return;
}
}
int main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int t;
cin >> t;
while (t--) {
solve();
}
return 0;
}
B. 移动到末端
https://codeforces.com/contest/2104/problem/B
每次测试时限:2 秒
每次测试的内存限制:512 兆字节
输入:标准输入
输出:标准输出
给你一个由 n n n 个整数组成的数组 a a a。
对于从 1 1 1 到 n n n 的每个整数 k k k,你必须执行以下操作:
- 从 a a a 中任意选择一个元素,将其移动到数组的右端(可以选择最后一个元素,这样数组就不会改变);
- 打印 a a a 的最后 k k k 个元素的总和;
- 将第一步中选择的元素移动到原来的位置(恢复原来的数组 a a a)。
每移动 k k k 个元素,就选择一个元素,这样打印出的值就是可能的最大值。
计算每 k k k 次打印的值。
输入
第一行包含一个整数 t t t( 1 ≤ t ≤ 1 0 4 1 \le t \le 10^4 1≤t≤104)— 测试用例数。
每个测试用例由两行组成:
- 第一行包含一个整数 n n n( 1 ≤ n ≤ 2 ⋅ 1 0 5 1 \le n \le 2 \cdot 10^5 1≤n≤2⋅105);
- 第二行包含 n n n 个整数 a 1 , a 2 , … , a n a_1, a_2, \dots, a_n a1,a2,…,an( 1 ≤ a i ≤ 1 0 9 1 \le a_i \le 10^9 1≤ai≤109)。
输入的附加限制:所有测试用例中 n n n 的总和不超过 2 ⋅ 1 0 5 2 \cdot 10^5 2⋅105。
输出
为每个测试用例打印 n n n 个整数。这些整数的第 i i i 个应该等于 k = i k=i k=i 时可以打印的最大值。
解题思路:计算前缀和与最大值
-
计算前缀和:
使用数组pre
存储前缀和,pre[i]
表示从数组开头到第 i i i 个元素的和。 -
计算前缀最大值:
使用数组pre_max
存储从数组开头到第 i i i 个元素的最大值。 -
计算每个 k k k 的最大和:
对于每个 k k k,计算最后 k k k 个元素的最大和:
最大和等于pre_max[n - i + 1]
(移动到末尾的最大值)加上pre[n] - pre[n - i + 1]
(剩余部分的和)。 -
输出结果:
按顺序输出每个 k k k 的最大和。
AC Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5 + 9;
ll a[N], pre[N], pre_max[N];
void solve() {
int n;
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
pre[i] = a[i] + pre[i - 1];
}
pre_max[1] = a[1];
for (int i = 2; i <= n; i++) {
pre_max[i] = max(pre_max[i-1], a[i]);
}
ll ans = 0;
for (int i = 1; i <= n; i++) {
ans = pre_max[n-i+1];
if (i > 1) {
ans += pre[n] - pre[n - i + 1];
}
cout << ans << " ";
}
cout << endl;
}
int main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int t;
cin >> t;
while (t--) {
solve();
}
return 0;
}
C. 纸牌游戏
https://codeforces.com/contest/2104/problem/C
每次测试时限:2 秒
每次测试的内存限制:512 兆字节
输入:标准输入
输出:标准输出
爱丽丝和鲍勃正在玩一个游戏。他们有 n n n 张牌,编号从 1 1 1 到 n n n。游戏开始时,其中一些牌给了爱丽丝,其余的给了鲍勃。
当且仅当 i > j i > j i>j 时,牌号为 i i i 的牌战胜牌号为 j j j 的牌,有一个例外:牌号为 1 1 1 的牌战胜牌号为 n n n 的牌。
只要每个玩家至少有一张牌,游戏就继续进行。在每个回合中,都会发生以下情况:
- 爱丽丝从自己的牌中选出一张,牌面朝上放在桌上;
- 鲍勃看到爱丽丝的牌,从自己的牌中选择一张牌,面朝上放在桌上;
- 如果爱丽丝的牌赢了鲍勃的牌,那么两张牌都由爱丽丝拿走。
- 否则,两张牌都由鲍勃拿走。
玩家可以使用自己在前一个回合中拿到的牌。
回合开始时没有牌的玩家输。如果双方都以最佳方式出牌,谁会赢?
输入
第一行包含一个整数 t t t( 1 ≤ t ≤ 5000 1 \le t \le 5000 1≤t≤5000)— 测试用例数。
每个测试用例由两行组成:
- 第一行包含一个整数 n n n( 2 ≤ n ≤ 50 2 \le n \le 50 2≤n≤50)— 卡片数量;
- 第二行包含
n
n
n 个字符,每个字符要么是
A
,要么是B
。如果第 i i i 个字符是A
,那么卡片编号 i i i 最初就会交给 Alice;否则,就会交给 Bob。
输入的附加限制:在每个测试用例中,至少有一张卡片最初给了爱丽丝,至少有一张卡片最初给了鲍勃。
输出
对于每个测试案例,如果爱丽丝以最佳下法获胜,则输出 Alice
;如果鲍勃获胜,则输出 Bob
。可以证明,如果双方都以最佳方式下棋,游戏肯定会在有限的回合数内结束,其中一方获胜。
解题思路:
特殊情况处理:
- 如果
n
=
2
n = 2
n=2,直接根据牌的分配判断胜负:
- 如果爱丽丝有1号牌且鲍勃有 n n n号牌,爱丽丝赢。
- 如果鲍勃有1号牌且爱丽丝有 n n n号牌,鲍勃赢。
- 如果某人同时有1号和 n n n号牌则直接获胜。
一般情况处理:
-
如果爱丽丝有1号牌且鲍勃有 n n n 号牌:
- 如果鲍勃有其他牌,鲍勃赢。
- 否则,爱丽丝赢。
-
如果鲍勃有1号牌且爱丽丝有 n n n 号牌:
- 如果爱丽丝没有其他牌,鲍勃赢。
- 否则:
- 如果鲍勃没有其他牌,爱丽丝赢。
- 如果爱丽丝和鲍勃都有其他牌,则比较两人最大的牌,谁的大谁就赢。
AC Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5 + 9;
void solve() {
int n;
cin >> n;
string s;
cin >> s;
if(s[0]=='A'&&s[n-1]=='B' && n == 2){
cout << "Alice" << endl;
return;
}
if(s[0]=='B'&&s[n-1]=='A' && n == 2){
cout << "Bob" << endl;
return;
}
if(s[0]=='B'&&s[n-1]=='B'){
cout << "Bob" << endl;
return;
}
if(s[0]=='A'&&s[n-1]=='A'){
cout << "Alice" << endl;
return;
}
vector<int> a, b;
for(int i=1;i<n-1;i++){
if(s[i]=='A'){
a.push_back(i+1);
}
else{
b.push_back(i+1);
}
}
if(s[0]=='A' && s[n-1]=='B'){
if(b.size()!=0){
cout << "Bob" << endl;
return;
}
else{
cout << "Alice" << endl;
return;
}
}
if(s[0]=='B' && s[n-1]=='A'){
if(a.size()==0){
cout << "Bob" << endl;
return;
}
else{
if(b.size()==0){
cout << "Alice" << endl;
return;
}
else{
if(a.back()<b.back()){
cout << "Bob" << endl;
return;
}
else{
cout << "Alice" << endl;
return;
}
}
}
}
}
int main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int t;
cin >> t;
while (t--) {
solve();
}
return 0;
}