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;
}