[Codeforce刷题3]

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 1t104)— 测试用例数。

每个测试用例的唯一一行包含三个整数 a a a, b b b c c c 1 ≤ a , b , c ≤ 1 0 8 1 \le a, b, c \le 10^8 1a,b,c108)— 分别是第一副牌、第二副牌和第三副牌的张数。

输入的额外限制: 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 aavg b − a v g b - avg bavg c − a v g c - avg cavg
    如果 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,你必须执行以下操作:

  1. a a a 中任意选择一个元素,将其移动到数组的右端(可以选择最后一个元素,这样数组就不会改变);
  2. 打印 a a a 的最后 k k k 个元素的总和;
  3. 将第一步中选择的元素移动到原来的位置(恢复原来的数组 a a a)。

每移动 k k k 个元素,就选择一个元素,这样打印出的值就是可能的最大值

计算每 k k k 次打印的值。

输入

第一行包含一个整数 t t t 1 ≤ t ≤ 1 0 4 1 \le t \le 10^4 1t104)— 测试用例数。

每个测试用例由两行组成:

  • 第一行包含一个整数 n n n 1 ≤ n ≤ 2 ⋅ 1 0 5 1 \le n \le 2 \cdot 10^5 1n2105);
  • 第二行包含 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 1ai109)。

输入的附加限制:所有测试用例中 n n n 的总和不超过 2 ⋅ 1 0 5 2 \cdot 10^5 2105

输出

为每个测试用例打印 n n n 个整数。这些整数的第 i i i 个应该等于 k = i k=i k=i 时可以打印的最大值。

解题思路:计算前缀和与最大值

  1. 计算前缀和
    使用数组 pre 存储前缀和,pre[i] 表示从数组开头到第 i i i 个元素的和。

  2. 计算前缀最大值
    使用数组 pre_max 存储从数组开头到第 i i i 个元素的最大值。

  3. 计算每个 k k k 的最大和
    对于每个 k k k,计算最后 k k k 个元素的最大和:
    最大和等于 pre_max[n - i + 1](移动到末尾的最大值)加上 pre[n] - pre[n - i + 1](剩余部分的和)。

  4. 输出结果
    按顺序输出每个 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 的牌。

只要每个玩家至少有一张牌,游戏就继续进行。在每个回合中,都会发生以下情况:

  1. 爱丽丝从自己的牌中选出一张,牌面朝上放在桌上;
  2. 鲍勃看到爱丽丝的牌,从自己的牌中选择一张牌,面朝上放在桌上;
    • 如果爱丽丝的牌赢了鲍勃的牌,那么两张牌都由爱丽丝拿走。
    • 否则,两张牌都由鲍勃拿走。

玩家可以使用自己在前一个回合中拿到的牌。

回合开始时没有牌的玩家输。如果双方都以最佳方式出牌,谁会赢?

输入

第一行包含一个整数 t t t 1 ≤ t ≤ 5000 1 \le t \le 5000 1t5000)— 测试用例数。

每个测试用例由两行组成:

  • 第一行包含一个整数 n n n 2 ≤ n ≤ 50 2 \le n \le 50 2n50)— 卡片数量;
  • 第二行包含 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. 如果爱丽丝有1号牌且鲍勃有 n n n 号牌

    • 如果鲍勃有其他牌,鲍勃赢。
    • 否则,爱丽丝赢。
  2. 如果鲍勃有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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Almond_s

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值