官方题解 | 挑战赛#27
2026-01-26 09:35:49
发布于:浙江
挑战赛27题解
本次题目的总体难度如下,各位选手可以借此评估一下自身的技术水平
| 题目编号 | 题目标题 | 难度 |
|---|---|---|
| T1 | 午枫的矩形 | 入门 |
| T2 | 午枫的字符串移动2 | 入门 |
| T3 | 午枫打砖块 | 普及/提高- |
| T4 | 午枫的子序列之和 | 普及/提高- |
| T5 | 午枫的星星树 | 普及- |
| T6 | 午枫的数字华容道 | 普及/提高- |
T1 午枫的矩形
题目大意
给定一个矩阵,判断这个矩阵的任意子矩阵是否满足 。
解题思路
由于数据范围只有 ,所有直接四层循环嵌套枚举左上角和右下角,同时也能知道左下角和右上角的坐标,直接计算判断即可。
参考代码
#include <bits/stdc++.h>
using namespace std;
const int N = 60;
int n,m;
int a[N][N];
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>a[i][j];
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
for(int x=i+1;x<=n;x++){
for(int y=j+1;y<=m;y++){
if(a[i][j]+a[x][y]>a[x][j]+a[i][y]){
cout<<"No"<<endl;
return 0;
}
}
}
}
}
cout<<"Yes"<<endl;
return 0;
}
T2 午枫的字符串移动2
题目大意
给定一个字符串,可以进行左移和右移的操作任意次,找到所有可以得到的字符串中字典序最小以及最大的字符串。
解题思路
因为可以操作任意次,所以只要单独往一个方向不断移动并且更新字典序最小和最大的字符串即可。
这里可以直接使用 string 类型进行移动的操作,并且也可以使用 min 和 max 函数进行比较字典序大小。
参考答案
#include <bits/stdc++.h>
using namespace std;
const int N = 1010;
int main(){
string s;cin>>s;
string mi=s;
string mx=s;
int n=s.size();
for(int i=1;i<=n;i++){
s=s.back()+s;
s.pop_back();
mi=min(mi,s);
mx=max(mx,s);
}
cout<<mi<<endl;
cout<<mx<<endl;
return 0;
}
T3 午枫打砖块
题目大意
给定 行砖块,每行向右无限延伸并且有且有一段连续的区间为奖励砖,每次可以选择一个区间长度 ,并且将这 列每行所有的砖块都破坏,奖励砖只要被破坏一个格子就会被全部破坏,求将所有奖励砖都破坏需要的最少操作次数。
解题思路
这是一道经典的贪心问题,在排序时我们会想到,如果破坏一个奖励砖的最右端,那么就会破坏更多的奖励砖,所以我们按照右端点排序,模拟每次打破当前剩余第一个奖励砖的最右端即可。
参考答案
#include <bits/stdc++.h>
using namespace std;
const int N = 200010;
struct P{
int l,r;
}p[N];
bool cmp(P a, P b){
return a.r<b.r;
}
int main(){
int n,d;cin>>n>>d;
for(int i=1;i<=n;i++) cin>>p[i].l>>p[i].r;
sort(p+1,p+n+1,cmp);
int now=0;
int res=0;
for(int i=1;i<=n;i++){
if(p[i].l>now){
res++;
now=p[i].r+d-1;
}
}
cout<<res<<endl;
return 0;
}
T4 午枫的子序列之和
题目大意
给定一个长度为 的数组和一个整数 ,求数组 的所有连续子序列中,元素之和等于 的个数。
解题思路
首先我们可以预处理前缀和数组 ,即需要求区间满足 的区间个数。问题就转化成了非常经典的问题。
枚举区间右端点 ,同时统计已枚举前缀每个 的个数,那么对于这个 ,对答案贡献为满足 的所有 的个数。那么问题又进一步简化为:统计 的个数。注意到数据范围无法用桶数组直接记录元素个数,考虑使用离散化或 map 直接统计都可完成。
参考代码
方法一:map
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 200010;
ll a[N], s[N];
int main(){
ll n,k;cin>>n>>k;
map<ll,ll>cnt;
for(int i=1;i<=n;i++){
cin>>a[i];
s[i]=s[i-1]+a[i];
}
cnt[0]=1;
ll res=0;
for(int i=1;i<=n;i++){
res+=cnt[s[i]-k];
cnt[s[i]]++;
}
cout<<res<<endl;
return 0;
}
方法二:离散化
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 200010;
ll a[N],s[N];
ll all[N*2];
ll cnt[N*2];
int idx;
int find(ll x,int sz) {
return lower_bound(all,all+sz,x)-all;
}
int main(){
ll n,k;
cin>>n>>k;
for(int i=1;i<=n;i++){
cin>>a[i];
s[i]=s[i-1]+a[i];
}
for(int i=0;i<=n;i++){
all[idx++]=s[i];
all[idx++]=s[i]-k;
}
sort(all,all+idx);
int m=unique(all,all+idx)-all;
int pos=find(0,m);
cnt[pos]=1;
ll res=0;
for(int i=1;i<=n;i++) {
int pos=find(s[i]-k,m);
res+=cnt[pos];
pos=find(s[i],m);
cnt[pos]++;
}
cout<<res<<endl;
return 0;
}
T5 午枫的星星树
题目大意
给定一棵树,问是否存在一个点与其他所有点直接相连。
解题思路
记录所有点的度数,判断是否存在一个点的度数为 即可。
参考代码
#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
int in[N];
int main(){
int n;cin>>n;
for(int i=1;i<n;i++){
int a,b;cin>>a>>b;
in[a]++;
in[b]++;
}
for(int i=1;i<=n;i++){
if(in[i]==n-1){
cout<<"Yes"<<endl;
return 0;
}
}
cout<<"No"<<endl;
return 0;
}
T6 午枫的数字华容道
题目大意
有 个点 条边的无向图,其中有 个数字放置在不同点上,有一个没有数字的点,可以通过移动将数字移动到相邻没有数字的点上,求最终将数字 分别放在顶点 上的最少操作次数。
解题思路
我们可以将 个顶点上所存放的数字用字符串表示状态,例如 254806137 表示顶点 存放数字 ,顶点 存放数字 ,依此类推,特殊地,数字 表示该点为空。那么终点就可以用 123456780 表示。
由于每次移动都会从一种状态变为另一种状态,我们不妨将每种状态看作一个结点,那么所有状态以及状态与状态之间的变换就可以形成一张无向图,于是我们只需要在图上用 跑最短路即可。由于结点是以字符串表示的,所以可以使用 map 存储从起点状态到达所有状态结点的最短路径长度。
参考代码
#include <bits/stdc++.h>
using namespace std;
const int N = 200010;
vector<int>v[N];
int main(){
int m;cin>>m;
for(int i=1;i<=m;i++){
int a,b;cin>>a>>b;
v[a].push_back(b);
v[b].push_back(a);
}
string s=" 000000000";
for(int i=1;i<=8;i++){
int x;cin>>x;
s[x]=i+'0';
}
queue<string>q;
map<string,bool>vis;
map<string,int>d;
q.push(s);
vis[s]=true;
d[s]=0;
while(!q.empty()){
auto t=q.front();q.pop();
int pos=t.find('0');
for(auto x:v[pos]){
string tmp=t;
tmp[x]=t[pos];
tmp[pos]=t[x];
if(vis[tmp]) continue;
q.push(tmp);
vis[tmp]=true;
d[tmp]=d[t]+1;
}
}
if(vis[" 123456780"]) cout<<d[" 123456780"]<<endl;
else cout<<-1<<endl;
}
全部评论 41
qp!
但是为什么前五题有原题。
3天前 来自 北京
4?我怎么不知道
昨天 来自 江苏
3t
昨天 来自 浙江
3111
16小时前 来自 广东
0
6
19小时前 来自 广东
3......
19小时前 来自 四川
21
昨天 来自 浙江
21
昨天 来自 浙江
2所以为什么比赛的难度不是递增的
3小时前 来自 重庆
1.......
.......
.......18小时前 来自 北京
1teffgh
19小时前 来自 北京
1t
20小时前 来自 北京
1顶顶顶
22小时前 来自 北京
11
昨天 来自 浙江
1qp
昨天 来自 江苏
11
3小时前 来自 浙江
06
13小时前 来自 广东
0厉害
14小时前 来自 山东
0懂了,但没完全懂…
14小时前 来自 河南
0顶顶顶顶顶顶
15小时前 来自 浙江
0666
15小时前 来自 广东
0666
15小时前 来自 广东
0666
15小时前 来自 广东
0











































有帮助,赞一个