官方题解 | 挑战赛#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;
}
全部评论 116
qp!
但是为什么前五题有原题。
1周前 来自 北京
13?我怎么不知道
1周前 来自 江苏
10t
1周前 来自 浙江
10111
6天前 来自 广东
6
6
6天前 来自 广东
9求赞!!!



5天前 来自 浙江
1
......
6天前 来自 四川
51
1周前 来自 浙江
51
1周前 来自 浙江
56
5天前 来自 浙江
4所以为什么比赛的难度不是递增的
6天前 来自 重庆
4因为题目里没说(
3天前 来自 浙江
1
test
昨天 来自 山东
2.......
.......
.......6天前 来自 北京
26,



5天前 来自 浙江
0太黄了
昨天 来自 上海
0
顶
昨天 来自 浙江
1为了罐头,给你点个赞
3天前 来自 浙江
1teffgh
6天前 来自 北京
1t
6天前 来自 北京
1顶顶顶
6天前 来自 北京
11
1周前 来自 浙江
1qp
1周前 来自 江苏
1666
12小时前 来自 浙江
01
12小时前 来自 新疆
06
14小时前 来自 北京
0pp
14小时前 来自 江苏
0



























































有帮助,赞一个