官方题解 | 挑战赛#28
2026-02-23 00:35:58
发布于:江苏
官方题解 | 挑战赛#28
本次题目的总体难度如下,各位选手可以借此评估一下自身的技术水平
| 题目编号 | 题目标题 | 难度 |
|---|---|---|
| T1 | 午枫的翻转 | 入门 |
| T2 | 午枫的卡片交换 | 普及- |
| T3 | 午枫的石头剪刀布大赛 | 普及- |
| T4 | 午枫的复制魔法 | 普及/提高- |
| T5 | 午枫的用户记录 | 普及/提高- |
| T6 | 午枫的数字分离 | 普及/提高- |
T1 午枫的翻转
题目大意
给定一个字符串和一个区间,输出翻转这段区间后的字符串。
解题思路
直接模拟或使用 reverse 函数即可。
参考代码
方法一
#include <bits/stdc++.h>
using namespace std;
int main(){
int l,r;cin>>l>>r;
string s;cin>>s;
reverse(s.begin()+l-1,s.begin()+r);
cout<<s<<endl;
return 0;
}
方法二
#include <bits/stdc++.h>
using namespace std;
int main(){
int l,r;cin>>l>>r;
l--,r--;
string s;cin>>s;
for(int i=0;i<l;i++) cout<<s[i];
for(int i=r;i>=l;i--) cout<<s[i];
for(int i=r+1;i<s.size();i++) cout<<s[i];
return 0;
}
T2 午枫的卡片交换
题目大意
给定两个字符串 ,问能否交换 的相邻两个字符最多一次,使得 。
解题思路
枚举模拟每个相邻位置的交换,判断是否存在一个位置使得 即可。
参考代码
#include <bits/stdc++.h>
using namespace std;
int main(){
string a,b;cin>>a>>b;
int n=a.size();
a=' '+a;
b=' '+b;
int cnt=0;
for(int i=1;i<n;i++){
if(a[i]==b[i]) continue;
if(a[i]!=b[i] && a[i+1]!=b[i+1]){
if(a[i]==b[i+1] && a[i+1]==b[i]){
cnt++;
i++;
}
else{
cout<<"No"<<endl;
return 0;
}
}
else{
cout<<"No"<<endl;
return 0;
}
}
if(cnt<=1) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
return 0;
}
T3 午枫的石头剪刀布大赛
题目大意
有 个人参加石头剪刀布比赛,一共 轮,每轮结束后重新排名,问最终的排名如何。
解题思路
使用结构体存储每名选手的编号、出拳顺序以及获胜场数,便于后续进行排序。
对每一轮比赛判断每组选手的胜负关系,记录每位选手的胜场数,每轮比赛结束对整体进行排序。
最终输出最终排名即可。
参考代码
#include <bits/stdc++.h>
using namespace std;
const int N = 110;
struct P{
int id;
string s;
int cnt;
}p[N];
bool cmp(P a,P b){
if(a.cnt!=b.cnt) return a.cnt>b.cnt;
return a.id<b.id;
}
int main(){
int n,m;cin>>n>>m;
for(int i=1;i<=2*n;i++){
cin>>p[i].s;
p[i].s=' '+p[i].s;
p[i].id=i;
p[i].cnt=0;
}
for(int j=1;j<=m;j++){
for(int i=1;i<=2*n;i+=2){
if(p[i].s[j]=='G' && p[i+1].s[j]=='C') p[i].cnt++;
else if(p[i].s[j]=='C' && p[i+1].s[j]=='G') p[i+1].cnt++;
else if(p[i].s[j]=='C' && p[i+1].s[j]=='P') p[i].cnt++;
else if(p[i].s[j]=='P' && p[i+1].s[j]=='C') p[i+1].cnt++;
else if(p[i].s[j]=='P' && p[i+1].s[j]=='G') p[i].cnt++;
else if(p[i].s[j]=='G' && p[i+1].s[j]=='P') p[i+1].cnt++;
}
sort(p+1,p+2*n+1,cmp);
}
for(int i=1;i<=2*n;i++){
cout<<p[i].id<<endl;
}
return 0;
}
T4 午枫的复制魔法
题目大意
给定一个数组 ,将它无限复制得到新的数组 ,从前往后依次累加,找出第一次使得累加和超过 的位置。
解题思路
直接一个一个累加计算判断很明显是通过不了的。设 为数组 所有元素的和,于是可以 计算出可以用最多多少个 ,剩下的部分一定能被数组 中某一个前缀超过, 遍历判断即可。
参考答案
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 100010;
ll a[N];
int main(){
ll n;cin>>n;
ll sum=0;
for(int i=1;i<=n;i++){
cin>>a[i];
sum+=a[i];
}
ll x;cin>>x;
ll res=x/sum*n;
x%=sum;
for(int i=1;i<=n;i++){
res++;
x-=a[i];
if(x<0){
cout<<res<<endl;
return 0;
}
}
return 0;
}
T5 午枫的用户记录
题目大意
给出 名用户的起始登录时间以及连续登录天数,问对于每一个满足 的整数 ,恰好有 人登录的天数。
解题思路
对于每一名用户,其对应登录的时间为一段连续的区间,不难想到使用差分前缀和来维护每天登录的人数。但由于数据范围较大,无法直接使用数组进行维护,考虑离散化,仅记录差分记录的时间点,因为前缀和后,相邻差分数组元素之间的值都是相等的,所以我们得到这段区间的值 后可以直接计算出这段区间的长度 ,即为恰好有 人的天数需要增加 。
参考代码
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 200010;
int l[N],r[N];
int d[2*N];
int cnt[N];
int main(){
int n;cin>>n;
vector<int>a;
for(int i=1;i<=n;i++){
cin>>l[i]>>r[i];
a.push_back(l[i]);
a.push_back(l[i]+r[i]);
}
sort(a.begin(),a.end());
a.erase(unique(a.begin(),a.end()),a.end());
map<int,int>mp,id;
int idx=0;
for(auto x:a){
mp[x]=++idx;
id[idx]=x;
}
for(int i=1;i<=n;i++){
d[mp[l[i]]]++;
d[mp[l[i]+r[i]]]--;
}
for(int i=1;i<=idx;i++) d[i]+=d[i-1];
for(int i=1;i<idx;i++){
int L=id[i],R=id[i+1]-1;
cnt[d[i]]+=R-L+1;
}
for(int i=1;i<=n;i++) cout<<cnt[i]<<" ";
return 0;
}
T6 午枫的数字分离
题目大意
将给出的 进行重新排列,然后分离成两个不带前导零的正整数,求分离得到的两个数的乘积的最大值。
解题思路
考虑 或二进制枚举将所有分离情况全都找出来,并且判断分离是否合法,然后记录最大值即可。
参考代码
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 3010;
bool rcmp(int a,int b){return a>b;}
int main(){
string s;cin>>s;
sort(s.begin(),s.end(),rcmp);
int n=s.size();
ll ans=0;
for(ll S=0;S<(1ll<<n);S++){
string a,b;
for(int i=0;i<n;i++){
if(S>>i&1) a+=s[i];
else b+=s[i];
}
if(a.size()==0 || a[0]=='0') continue;
if(b.size()==0 || b[0]=='0') continue;
ll x=stoll(a),y=stoll(b);
ans=max(ans,x*y);
}
cout<<ans<<endl;
return 0;
}
这里空空如也




















有帮助,赞一个