A - aaaadaa

题意

给你一个字符串s和字符c1, c2. 要求将s中所有不是c1的字符替换为c2.

思路

用for循环遍历每个字符,然后逐个判断并替换即可.

题解

#include "stdio.h"

int main() {
    int n;
    char c1, c2;
    scanf("%d %c %c", &n, &c1, &c2);
    char s[n];
    scanf("%s", s);
    for(int i = 0; i < n; i++){
        if(s[i] != c1) {
            s[i] = c2;
        }
    }
    printf("%s", s);
    return 0;
}

B - ARC Division

题意

你有一个初始评分rating,每当参加一场比赛,并且你的分数符合评分要求时,你的分数就会加上得分A。问若干场比赛后你的评分是多少?

思路

对于每场比赛,先判断参加的是分区1还是分区2,然后对于每个分区,判断是否符合该分区的评分要求,如果是,则加上评分,否则什么都不做。

题解

#include "stdio.h"

int main() {
    int n, rating;
    scanf("%d %d", &n, &rating);
    for(int i = 0; i < n; i++){
        int divison, r;
        scanf("%d %d", &divison, &r);
        if(divison == 1){
            if(1600 <= rating && rating <= 2799) {
                rating += r;
            }
        } else {
            if(1200 <= rating && rating <= 2399) {
                rating += r;
            }
        }
    }
    printf("%d\n", rating);
    return 0;
}

C - Perfect Standings

题意

某场比赛有5道题目,每道题都有一个分数,从按分数大到小输出解答题目的组合(如ACD,表示解答了A,C,D这三题),相同的分数按照字典序小的在前(如B在E前面,AC在BD前面)。

思路

先获取全部组合的分数以及对应字符串。然后再排序。

获取全部分数

将每个题目是否被解答视为0或1,那么用5位二进制数(00000 ~ 11111即0 ~ 31)即可表达每一种组合,我们可以从32递减(或从0递加)。然后用位运算&判断每一个组合都解答了哪些题目,并据此修改分数和组合名。

排序

可以用STL自带的sort函数,但是需要自己写比较函数

[](pair<int, string> a, pair<int, string> b){return a.first > b.first || (a.first == b.first && a.second < b.second);}

上文为lambda表达式,也叫匿名函数,它也起到函数的功能只是无需声明。 其中[]表示不捕获任何外部变量,()内为函数接收的形参,花括号内为函数体。 该比较函数需要满足严格弱序,以小于关系举例,即

  • 反自反:对于任意元素a,a < a 为假。
  • 反对称:如果a < b为真,则b < a为假。
  • 可传递:如果a < b且b < c为真,则a < c为真。
  • 不可比较关系可传递:如果a与b不可比,且b与c不可比,则a与c也不可比。(即等价关系可传递)

对于

a.first > b.first || (a.first == b.first && a.second < b.second)

先判断a的分数是否大于b,如果是则a大于b
否则判断它两分数是否相等,如果是,继续判断a的名字的字典序是否小于,如果是,则a大于b。 在上述代码中,在比较名字前需要先判断分数是否相等,因为如果在b分数大于a的分数时,进行了名字的比较,就会导致排序出错。

题解

#include <bits/stdc++.h>

using namespace std;
int main(){
    vector<int> scores(5);
    for(int i = 0; i < 5; i++) cin >> scores[i];
    int j = 32;
    vector<pair<int, string>> ans;
    while(j--){
        string name = "";
        int score = 0;
        for(int k = 0; k < 5; k++){
            if((j & (0b10000 >> k)) != 0) {
                name += "ABCDE"[k];
                score += scores[k];
            }
        }
        ans.push_back({score, name});
    }
    sort(ans.begin(), ans.end(), [](pair<int, string> a, pair<int, string> b){return a.first > b.first || (a.first == b.first && a.second < b.second);});
    for(int i = 0; i < 32; i++) {
        cout << ans[i].second << endl;
    }
}

D - Repeated Sequence

题意

给你一个无穷数列,问其中是否有一个连续非空子序列,使得这一段序列的和为S

思路

首先,子序列的长度有两种情况,一是小于周期N,二是大于周期N。
对于大于周期N的序列,其中必然包含若干个完整的周期,于是我们可以移除所有完整的周期。那么剩下的序列长度必然小于单个周期。
但是这存在一个问题就是,我移除完整周期后,剩下的子序列可能不连续
比如从1 231231 2中移除了231231,就变成了分开的1---------2,为了解决这个序列可能一半在头,一半在尾的问题,我们需要将两个序列首尾拼接起来,变成一个两倍长的序列,这就化归到了第一种情况。
对于第一种情况长度小于周期N,看见连续的子序列和,自然可以想到前缀和。于是我们相当于是在前缀和数组里面找两个数,使得这两个数的差等于S。 即S_j - S_i == target(其中j > i),再移一下项成S_i + target = S_j,这其实就变成了本次语法题中的第一题:两数之和。

题解

特别的,我们在下面的“两数之和”中并没有使用双循环的方法,而是使用了set来保存所有的值,这样可以将查找的复杂度降为O(log n).

#include <bits/stdc++.h>

using namespace std;

int main() {
    long long n, target;
    cin >> n >> target;
    vector<long long> nums(n);
    
    for (long long i = 0; i < n; i++) {
        cin >> nums[i];
    }
    
    const long long total_sum = accumulate(nums.begin(), nums.end(), 0LL);
    target %= total_sum;
    
    vector<long long> double_nums = nums;
    double_nums.insert(double_nums.end(), nums.begin(), nums.end());
    
    set<long long> presum;
    presum.insert(0);  // 提前插入0,因为长度可能恰好是周期的整数倍
    long long current_sum = 0;
    
    for (auto num : double_nums) {
        current_sum += num;
        presum.insert(current_sum);
    }
    
    for (auto p : presum) {
        if (presum.find(p + target) != presum.end()) {
            cout << "Yes" << endl;
            return 0;
        }
    }
    
    cout << "No" << endl;
    return 0;
}