# 非官方题解 | 挑战赛#28
2026-02-23 10:47:43
发布于:浙江
T1:午枫的翻转
本题太水,就直接放代码了哈
namespace CuSn{
void solve(){
int l,r;
string s;
cin>>l>>r>>s;
l--;r--;
while(l<r){
swap(s[l],s[r]);
l++;
r--;
}
cout<<s<<'\n';
}
}
T2:午枫的卡片交换
思路解析
题目要求:最多一次交换相邻字符,能否使字符串 变成 。
情况分析
- 如果 和 已经相同,则不需要交换,直接输出
Yes。 - 否则,只能交换一次相邻字符,意味着 和 最多只能有两处不同(交换的那一对位置及其相邻影响)。
- 更简单的做法:直接枚举所有相邻交换,检查是否得到 。
由于 , 枚举完全可行。
代码实现
namespace CuSn{
void solve(){
string s,t;
cin>>s>>t;
if(s==t){
cout<<"Yes\n";
return;
}
for(int i=0;i****.size();i++){
swap(s[i],s[i+1]);
if(s==t){
cout<<"Yes\n";
return;
}
swap(s[i],s[i+1]);
}
cout<<"No\n";
}
}
T3: 午枫的石头剪刀布大赛
思路解析
这是一个模拟 + 排序的问题。
- 有 名选手,编号 ,进行 轮比赛。
- 每轮根据上一轮的排名进行配对:排名 和 对战。
- 每场比赛根据手势决定胜负(G石头、C剪刀、P布),胜者胜场 。
- 每轮结束后重新排名:先按胜场数降序,相同则编号小的靠前。
- 最终输出 轮后的最终排名(即第 轮结束后的排名)。
实现步骤
- 读入 和每个选手每轮的手势( 行,每行 个字符)。
- 用一个数组或结构体记录每个选手的编号和胜场数,初始胜场为 。
- 对每一轮 (从 到 ):
- 按照当前排名(胜场降序,编号升序)排序。
- 两两配对进行比赛,根据手势更新胜场。
- 最后按排名输出选手编号。
代码实现
namespace CuSn{
int n,m;
string s[105];
struct node{
int id,w;
}p[105];
bool cmp(node a,node b){
if(a.w!=b.w)return a.w>b.w;
return a.id<b.id;
}
int win(char a,char b){
if(a==b)return 0;
if(a=='G'&&b=='C')return 1;
if(a=='C'&&b=='P')return 1;
if(a=='P'&&b=='G')return 1;
return -1;
}
void solve(){
cin>>n>>m;
n*=2;
for(int i=1;i<=n;i++){
cin>>s[i];
p[i]={i,0};
}
for(int j=0;j<m;j++){
sort(p+1,p+n+1,cmp);
for(int k=1;k<=n;k+=2){
int a=p[k].id,b=p[k+1].id;
int res=win(s[a][j],s[b][j]);
if(res==1)p[k].w++;
else if(res==-1)p[k+1].w++;
}
}
sort(p+1,p+n+1,cmp);
for(int i=1;i<=n;i++)cout<<p[i].id<<'\n';
}
}
T4:午枫的复制魔法
思路解析
数组 无限复制得到数组 ,求累加和第一次超过 的位置。
关键思路
- 先计算一轮的总和 。
- 如果 (本题保证 ,所以 ),不需要考虑这种情况。
- 完整轮数 ,这些完整轮贡献的位置数为 ,总和为 。
- 剩余需要累加的量 。
- 从 开始依次累加,直到累加和 ,此时总位置 = ( 是当前累加到的位置)。
代码实现
namespace CuSn{
typedef long long ll;
void solve(){
ll n;
cin>>n;
vector<ll> a(n+1);
ll sum=0;
for(ll i=1;i<=n;i++){
cin>>a[i];
sum+=a[i];
}
ll x;
cin>>x;
ll full=x/sum;
ll cur=full*sum;
ll ans=full*n;
for(ll i=1;i<=n;i++){
cur+=a[i];
ans++;
if(cur>x){
cout<<ans<<'\n';
return;
}
}
}
}
T5: 午枫的用户记录
思路解析
我们需要统计:恰好有 个用户同时登录的天数,。
关键观察
- 每个用户的登录区间是 (左闭右开,因为最后一天是 ,所以结束时间是 )。
- 我们可以使用差分数组的思想,但 和 高达 ,不能直接开数组。
- 用
map存储差分:在 处 ,在 处 。 - 遍历
map(天然按时间排序),维护当前登录人数 ,以及上一时间点 。 - 每一段 长度 的区间内,登录人数都是 。
- 将该段长度累加到 中。
代码实现
namespace CuSn{
typedef long long ll;
const int N=200005;
int n;
ll ans[N];
map<ll,int> mp;
void solve(){
cin>>n;
for(int i=1;i<=n;i++){
ll bg,cnt;
cin>>bg>>cnt;
mp[bg]++;
mp[bg+cnt]--;
}
ll cur=0,last=0;
for(auto &[pos,val]:mp){
if(last){
ll len=pos-last;
ans[cur]+=len;
}
cur+=val;
last=pos;
}
for(int i=1;i<=n;i++)cout<<ans[i]<<" \n"[i==n];
}
}
T6:午枫的数字分离
思路解析
题目要求:将 的各位数字重新排列,分成两个正整数(不能有前导零),使得它们的乘积最大。
关键观察
- ,最多 10 位数字,可以暴力枚举所有划分方式。
- 枚举所有子集分配,检查是否满足无前导零(两个数的首位不能是 0)。
- 对每个子集,将分配给第一个数的数字降序排列得到最大可能的数,第二个数同理。
- 计算乘积,更新最大值。
优化
- 由于数字可能重复,可以用
multiset或直接排序。 - 枚举所有非空真子集(至少给每个数一个数字)。
代码实现
namespace CuSn{
typedef long long ll;
string s;
int len;
ll ans;
vector<int> d;
ll get(vector<int> v){
sort(v.begin(),v.end(),greater<int>());
ll res=0;
for(int x:v)res=res*10+x;
return res;
}
void solve(){
cin>>s;
len=s.size();
d.resize(len);
for(int i=0;i<len;i++)d[i]=s[i]-'0';
int tot=1<<len;
for(int mask=1;mask<tot-1;mask++){
vector<int> a,b;
for(int i=0;i<len;i++){
if((mask>>i)&1)a.push_back(d[i]);
else b.push_back(d[i]);
}
if(a.empty()||b.empty())continue;
if(a[0]==0||b[0]==0)continue;
ll x=get(a),y=get(b);
if(x*y>ans)ans=x*y;
}
cout<<ans<<'\n';
}
}
我可爱的马蜂
全部评论 2
T5 用 map 存差分而不是排序,我认为您不是人类
5天前 来自 广东
0。
5天前 来自 浙江
0猜对了
4天前 来自 浙江
0
%%%
5天前 来自 浙江
0d
5天前 来自 浙江
0






















有帮助,赞一个