- 区
2026省赛初中组(题目&题解&思路解析)@霸王龙
- @ 2026-6-6 22:26:29
由于bwloj没有省赛初中组
所以我找来了初中的6题以及题解希望bwl置顶
题解纯手写无任何ai,用ai我是gay(注释除外)
题目我也改进了加粗下划线代码块标题等
爆肝4小时(包括做题时间)
题目来源于nh.51goc.com
思路解析部分有用到ai
结构(大小):{
题目
情境
题目
输入格式
输入格式
输出格式
输出格式
输入/输出例子1
输入:
输入
输出:
输出
(样例解释);
样例解释
思路解析;
思路解析
题解
题解
}
第1题 超速扣分(2026省赛选拔赛c1)
某地对车辆超速和低速行驶有如下扣分标准: 行驶速度低于规定最低时速的,扣 3 分; 超过规定最高时速,但超出比例不超过 20% 的,扣 3 分; 超过规定最高时速 20% 以上,但超出比例不超过 50% 的,扣 6 分; 超过规定最高时速 50% 以上的,扣 12 分; 正常行驶在规定最低时速和规定最高时速之间的,不扣分。 给定规定最高时速、规定最低时速和当前时速,请你计算应扣多少分。 注意:如果规定最高时速不大于规定最低时速,则该速度限制不合法,应输出 -1。
输入格式
输入一行,包含三个整数 H, L, V,分别表示规定最高时速、规定最低时速和当前时速。
输出格式
输出一行,包含一个整数,表示应扣分数。
如果规定最高时速不大于规定最低时速,输出 -1。
输入/输出例子1
输入:
50 20 70
输出:
6
样例解释
约定和数据范围
对于所有数据,保证:
0 ≤ H, L, V ≤ 10^9,
其中:
H 表示规定最高时速;
L 表示规定最低时速;
V 表示当前时速。
注意,判断超速比例时,应以规定最高时速 H 作为基准。
思路解析
合法性判断:首先检查输入的最高时速 H 和最低时速 L。若 L >= H,说明速度限制不合法,直接输出 -1。
正常行驶区间:若当前时速 V 满足 L <= V <= H,则属于正常行驶,不扣分。
低速行驶:若 V < L,根据规则,低于最低时速一律扣 3 分。
超速行驶:若 V > H,则需要计算超出比例 (V - H) / H,并按以下分段扣分:
超出比例 ≤ 20%:扣 3 分
20% < 超出比例 ≤ 50%:扣 6 分
超出比例 > 50%:扣 12 分
注意事项:
数值范围较大(≤ 1e9),使用 64 位整数存储。
比较比例时需用浮点数或交叉乘法避免精度问题(如 (V-H)100 <= H20)。
输出最终扣分数(0、3、6、12 或 -1)。
题解c++98
#include<bits/stdc++.h>
using namespace std;
long long g,d,a;int s;//g:最高时速, d:最低时速, a:当前时速, s:扣分
int main(){
cin>>g>>d>>a;//输入
if(d>=g){//若最低时速不小于最高时速输出-1
cout<<-1;
return 0;
}
else if(a>g){//超速情况
if((a-g)*1.0/g<=0.2)s=3;//超出≤20%扣3分
else if((a-g)*1.0/g>0.2&&(a-g)*1.0/g<=0.5)s=6;//超出20%~50%扣6分
else s=12;//超出>50%扣12分
}
else if(a<g)s=3;//低速情况先
cout<<(a>=d&&a<=g?0:s);//若在正常区间则0分,否则输出s
return 0;
}
第2题 小怪兽(2026省赛选拔赛c2)
有一只小怪兽正在排队吃能量团。小怪兽有一个当前体型大小, 每个能量团也有一个大小。小怪兽只能吃掉比自己小的能量团。具体规则如下:
如果小怪兽遇到的能量团大小严格小于自己的当前大小, 那么小怪兽会吃掉这个能量团,并且自己的大小会增加这个能量团的大小;
如果小怪兽遇到的能量团大小大于或等于自己的当前大小, 那么小怪兽会害怕并立刻逃跑,不再继续吃后面的能量团。
现在,小怪兽正面对一排能量团,并会按照输入顺序依次遇到它们。
已知小怪兽最终一定会遇到一个无法吃掉的能量团并逃跑。请你求出小怪兽逃跑时的大小。
输入格式
第一行输入一个正整数 S,表示小怪兽的初始大小。
接下来若干行, 每行包含一个正整数, 表示一个能量团的大小。小怪兽会按照输入顺序依次遇到这些能量团。
保证小怪兽最终一定会遇到一个大小大于或等于自身大小的能量团。
输出格式
输出一行,包含一个正整数,表示小怪兽逃跑时的大小。
输入/输出例子1
输入:
5
3
2
9
20
22
14
输出:
19
样例解释
对于所有数据,能量团数量不超过 105,保证小怪兽的初始大小和每个能量团的大小均为正整数,且不超过 10^9 。保证小怪兽最终一定会遇到一个大小大于或等于自身的能量团,并停止进食。
【样例1解释】:
小怪兽初始大小为 5。
它首先遇到大小为 3 的能量团,因为 3 < 5,所以可以吃掉。吃掉后,小怪兽大小变为:
5 + 3 = 8
接着遇到大小为 2 的能量团,因为 2 < 8,所以可以吃掉。吃掉后,小怪兽大小变为:
8 + 2 = 10
接着遇到大小为 9 的能量团,因为 9 < 10,所以可以吃掉。吃掉后,小怪兽大小变为:
10 + 9 = 19
接着遇到大小为 20 的能量团,因为 20 ≥ 19,小怪兽无法吃掉它,于是逃跑。
因此,小怪兽逃跑时的大小为 19。
思路解析
模拟进食过程:小怪兽从初始大小 S 开始,按顺序依次处理每个能量团。
判断能否吃掉:
若当前能量团大小 严格小于 怪兽当前大小,则吃掉:怪兽大小增加能量团大小,继续处理下一个。
若能量团大小 大于等于 怪兽当前大小,则无法吃掉,怪兽立即逃跑,此时怪兽的大小即为答案。
终止条件:题目保证一定会遇到一个无法吃掉的能量团,因此循环必然结束,无需额外处理文件尾。
数据类型:初始大小和能量团大小可达 1e9,且怪兽大小会累加,最大可能超过 32 位范围,需使用 64 位整数(long long)。
实现方式:循环读入每个能量团,若可以吃则累加,否则输出当前大小并结束程序。
题解c++98
#include<bits/stdc++.h>
using namespace std;
long long a,x;//a:小怪兽当前大小, x:当前能量团大小
int main(){
cin>>a;//输入
while(cin>>x){//循环读取每个能量团大小
if(a>x)a+=x;//吃
else {//不吃
cout<<a;//输出逃跑时的大小
return 0;
}
}
return 0;//可省略
}
第3题 短信压缩(2026省赛选拔赛c3)
小明最近办理了一个新的手机短信套餐。这个套餐的收费方式比较特殊: 发送短信时, 系统会按照短信中字符的数量进行计费。
小明发现,自己经常会在短信中连续输入很多相同的字符。例如: +++++=====.
为了减少需要发送的字符数量,小明想到了一种简单的压缩方法。
对于一段连续相同的字符,可以将它压缩为:连续出现的次数 该字符
例如,字符串 **+++===!!!!**可以压缩为: 3 + 3 = 4 !
因为它由 3 个连续的 +, 3 个连续的 =,以及 4 个连续的 ! 组成。
更一般地说, 一个连续块是指一段尽可能长的、由相同字符组成的连续子串。每个连续块在压缩后表示为该连续块的长度,后面跟着该连续块中的字符。
现在给定若干行字符串,请你按照上述规则对每一行字符串进行压缩。
输入格式
输入共 N + 1 行。
第一行包含一个正整数 N,表示接下来需要压缩的字符串行数。
接下来 N 行, 每行包含一个字符串。字符串长度至少为 1, 至多为 80, 且字符串中不包含空格。
输出格式
输出共 N 行。
第 i 行输出输入中第 i 个字符串的压缩结果。
每一行的压缩结果由若干组内容组成,每一组表示一个连续块,格式为:
连续出现的次数字符,同一行中相邻两组之间用一个空格隔开。
输入/输出例子1
输入:
4
+++===!!!!
777777......TTTTTTTTTTTT
(AABBC)
3.1415555
输出:
3 + 3 = 4 !
6 7 6 . 12 T
1 ( 2 A 2 B 1 C 1 )
1 3 1 . 1 1 1 4 1 1 4 5
样例解释
约定和数据范围
对于所有测试点,保证 1 ≤ N ≤ 10。
每个字符串长度至少为 1,至多为 80,且字符串中不包含空格。
思路解析
逐行处理:输入第一行为行数 N,随后 N 行每行一个字符串(长度 1~80,无空格)。
连续块划分:对每个字符串,从左到右扫描,找出所有“最长连续相同字符”的子串(连续块)。
压缩表示:每个连续块输出 长度 字符,相邻块之间用一个空格分隔。
扫描方法:
初始化当前字符为第一个字符,计数器为 1。
从第二个字符开始遍历:
若当前字符与上一个字符相同,计数器加 1。
若不同,则输出上一个块的计数和字符,然后重置当前字符为新字符,计数器为 1。
遍历结束后,输出最后一个块。
输出格式:每行压缩结果末尾无多余空格(或允许末尾空格,但一般要求规范),且每行结束后换行。
特殊情况:字符串长度为 1 时,直接输出 1 该字符。
题解c++98
#include<bits/stdc++.h>
using namespace std;
int n;string a;
int main(){
cin>>n;//输入行数
while(n--){
cin>>a;//读入一行字符串
char d=a[0];//当前块的字符,初始为第一个字符
int s=1;//当前块连续出现的次数
for(int i=1;i<a.size();i++){//从第二个字符开始遍历
if(a[i]!=a[i-1]){//如果当前字符与前一个不同,表示一个连续块结束
cout<<s<<' '<<d<<' ';//输出次数和字符
d=a[i];
s=1;//重置
}
else s++;//加1
}
cout<<s<<' '<<d<<'\n';//输出最后一个次数和字符
}
return 0;
}
第4题 哥德巴赫猜想(2026省赛选拔赛c4)
在数学中,有一个著名的猜想叫作哥德巴赫猜想:
任意一个大于 2 的偶数,都可以表示成两个质数之和。
例如:
20 = 3 + 17 = 7 + 13
现在, 学校数学兴趣小组正在研究这个猜想。给定一个大于等于 4 的偶数 N, 请你找出两个质数 p 和 q,使得:
p + q = N
如果有多种方案,请输出 p 最小的一组。
输入格式
输入共 1 行。
第一行包含一个偶数 N。
输出格式
输出一行,包含两个质数 p 和 q,中间用一个空格隔开。
要求满足:
p + q = N
如果存在多种方案,请输出 p 最小的一组。
输入/输出例子1
输入:
20
输出:
3 17
样例解释
约定和数据范围
对于所有测试点,保证 N 为偶数,且 4 ≤ N ≤ 100000。题目保证一定存在两个质数 p 和 q,满足:
p + q = N
思路分析
预处理质数表:由于 N N 最大为 10 5 10 5 ,可以先用埃氏筛法标记出 1 1 到 10 5 10 5 内所有数是否为质数。
枚举最小质数:从 2 2 开始从小到大枚举 i i(实际上从 1 1 开始也可以,但 1 1 不是质数),令 t
N − i t=N−i。
判断并输出:如果 i i 和 t t 都是质数,则输出 i i 和 t t 并结束程序。由于是从小到大枚举,第一个找到的解一定满足 p p 最小。
代码对应说明
数组 p 记录合数(p[i]=1 表示合数),初始化 p[1]=1。
双层循环完成埃氏筛。
主循环 for(long long i=1; i<n; i++) 枚举 i i,判断 !p[i] && !p[t] 即两个都是质数,输出即可。
题解c++98
#include<bits/stdc++.h>
using namespace std;
bool p[1000001];
long long n;
int main(){
p[1]=1;
for(long long i=2;i<=100000;i++){
if(!p[i])for(long long j=i+i;j<=100000;j+=i)p[j]=1;
}
cin>>n;
for(long long i=1;i<n;i++){
long long t=n-i;
if(!p[t]&&!p[i]){
cout<<i<<' '<<t;return 0;
}
}
return 0;
}
第5题 蜗牛路径(2026省赛选拔赛c5)
一只蜗牛正在无限大的方格网中爬行。方格网由大小相同的正方形格子组成, 蜗牛每次只能向东、西、南、北四个方向之一爬行,不能斜着爬。
蜗牛爬过的每一个格子都会留下黏液。也就是说, 只要蜗牛曾经到达过某个格子, 这个格子就会变成有黏液的格子。
蜗牛一开始所在的格子也会立刻变成有黏液的格子,但这不算作“进入有黏液的格子”。
给定蜗牛依次进行的若干次移动, 请你求出蜗牛在整个过程中一共多少次进入了已经有黏液的格子。
注意:
• 每次移动可能包含多格,蜗牛会一格一格地经过中间的格子;
• 如果蜗牛进入一个之前已经有黏液的格子,答案加 1;
• 同一个有黏液的格子可以被多次进入,每次进入都要计数。
输入格式
第一行输入一个正整数 N,表示蜗牛进行的移动次数。
接下来 N 行, 每行描述一次移动。每次移动由一个大写字母和一个正整数构成, 中间没有空格。
方向字母只可能是以下四种之一:
• N:向北移动;
• E:向东移动;
• S:向南移动;
• W:向西移动。
每次移动的距离不超过 20。
输出格式
输出一行,包含一个非负整数,表示蜗牛进入有黏液格子的次数。
样例1解释:
蜗牛一开始所在的格子已经有黏液,但不计入答案。
第一次移动 S2 时,蜗牛向南经过两个新格子。
第二次移动 N2 时,蜗牛向北回到之前经过的两个格子,因此答案增加 2。
第三次移动 S3 时,蜗牛又向南移动,其中前两个格子已经有黏液,因此答案再增加 2。
输入/输出例子1
输入:
3
S2
N2
S3
输出:
4
样例解释
对于所有测试点,保证 1 ≤ N ≤ 10^5,每次移动的距离为正整数且不超过 20。
思路分析
模拟每一步:维护当前坐标 (x,y)。对于每次移动,记录移动前的坐标 (x0,y0) 和移动后的坐标 (x1,y1)。
枚举经过的所有格子:由于移动方向是正交的,且距离 ≤20,因此从 (x0,y0) 到 (x1,y1) 经过的所有格子构成一条直线段。可以用双重循环遍历该线段上的每一个整数坐标点(注意包括起点和终点)。
判断是否已存在黏液:使用哈希表(unordered_map)记录每个坐标是否被访问过。对于当前遍历到的格子:
如果哈希表中已存在(值为1),则答案加1;
否则,将其标记为1。
注意:原题解代码中有一行 if(mp[un(x,y)]==1)s--; 可能是为了抵消起点重复计数的特殊处理,但实际思路中只需按上述方法模拟即可。最终输出累计的 s。
代码对应说明
un(x,y) 将坐标映射为 x*100000+y(因为坐标范围可能较大,但步数限制保证了差值在合理范围)。
移动前先记录起点,然后更新坐标,再对 x 和 x1、y 和 y1 排序以确保循环从小到大。
双重循环遍历矩形区域(由于移动是直线,实际遍历的是一行或一列,但这里用矩形也能正确覆盖所有经过的格子)。
使用 mp.count() 或 mp[ ] 检查是否已存在,若存在则累加,否则插入。
题解c++11
#include<bits/stdc++.h>
using namespace std;
struct node{
int x,y;
};
unordered_map<long long,int>mp;
int n,s;char v;
node g;
long long un(int x,int y){
return x*100000+y;
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
char q;int t;
cin>>q>>t;
int x=g.x,y=g.y;
if(mp[un(x,y)]==1)s--;
if(q=='N'){g.y-=t;}
if(q=='S'){g.y+=t;}
if(q=='W'){g.x-=t;}
if(q=='E'){g.x+=t;}
int mx=g.x,my=g.y;
if(mx<x)swap(mx,x);
if(my<y)swap(my,y);
for(int j=x;j<=mx;j++){
for(int k=y;k<=my;k++){
if(mp[un(j,k)]==1)s++;
else mp[un(j,k)]=1;
}
}
}
cout<<s;
return 0;
}
第6题 Happy! (2026省赛选拔赛c6)
UCF(United Credit Finance)公司正在运行一个简单的场景,以评估有多少客户对公司满意。UCF 有一名柜员(teller)为客户服务。
客户编号为 1 到 n,按顺序依次到达,即客户 1 最先到达,然后是客户 2,以此类推。任意两个客户的到达时间互不相同,且客户按照到达顺序依次被服务(不会乱序处理)。
正如你在排队时可能注意到的那样,有些客户会因为不耐烦而离开。给定 UCF 所有客户的信息,你需要判断哪些客户是满意的,即他们在被处理之前没有离开。
输入格式
第一行包含一个整数 n(1≤n≤10^3),表示到达的客户总数
接下来 n行,每行包含一位客户的信息(按客户编号顺序给出),依次为:
到达时间(1 到 10^4 之间的整数)
服务时间(1 到 10^4 之间的整数),表示柜员为该客户服务所需的时间(从开始服务时计算)
耐心时间(1 到 10^4 之间的整数),表示客户愿意等待的最长时间。若客户在耐心时间耗尽时仍未开始被服务,则会离开队列。注意:离开的客户不会占用柜员的时间。
输出格式
按顺序输出所有满意客户的编号(满意即被柜员服务,未提前离开)。
输入/输出例子1
输入:
7
50 10 5
52 5 4
58 20 5
85 7 10
86 10 1
88 20 3
89 30 3
输出:
1
3
4
7
样例解释
1 <= n <= 1000
到达时间、服务时间、耐心时间均为 1 到 10000 之间的整数
【样例解释】
柜员在时刻 60(50+10)处理完客户 1,下一位客户最早在时刻 60 开始服务。客户 2 在时刻 52 到达,耐心时间为 4,若到时刻 56(52+4)仍未开始服务则离开。由于柜员在时刻 60 才空闲,客户 2 离开,不占用柜员时间。客户 3 在时刻 58 到达,耐心时间为 5,最晚接受到时刻 63 才开始服务。柜员在时刻 60 开始服务客户 3,服务至时刻 80(60+20)。客户 4 在时刻 85 到达(柜员已空闲),立即开始服务,于时刻 92(85+7)结束。客户 5 在时刻 86 到达,耐心时间为 1,最晚接受到时刻 87 才开始服务,但柜员在时刻 92 才空闲,故离开。客户 6 在时刻 88 到达,耐心时间为 3,最晚接受到时刻 91 才开始服务,但柜员在时刻 92 才空闲,故离开。客户 7 在时刻 89 到达,耐心时间为 3,最晚接受到时刻 92 才开始服务,柜员恰好在时刻 92 空闲,故满意。
思路分析
第一个客户一定满意:因为没有人排队,到达后立即开始服务。记录其服务结束时间 = arr + serve。
依次处理后续客户:对于客户 i,需要找到它之前最后一个被服务的客户(即满意客户中编号最大的且小于 i 的那个)。
判断当前客户是否满意:
设前一个满意客户为 j,其服务结束时间为 finish_j。
当前客户的最晚可接受开始时间为 arr_i + patience_i。
如果 finish_j ≤ arr_i + patience_i,则当前客户可以等到柜员空闲,因此满意;否则离开。
若满意,更新柜员空闲时间:当前客户的实际开始服务时间 = max(arr_i, finish_j),结束时间 = 开始时间 + serve_i。
为方便计算,可以将 serve_i 更新为 serve_i + max(0, finish_j - arr_i),这样 arr_i + serve_i 就代表了新的结束时间。
输出所有满意客户的编号(按输入顺序,即编号升序)。
代码对应说明
数组 a[] 存储到达时间,b[] 存储服务时间(过程中会被修改为结束时间),c[] 存储耐心时间,f[] 标记客户是否满意。
对于客户 i,用变量 k 向前寻找最近的满意客户:while(!f[i-k]) k++; 得到最近满意客户的索引 i-k。
条件 a[i]+c[i] >= a[i-k]+b[i-k] 即 当前客户最晚接受时间 ≥ 前一个满意客户的结束时间,判断满意。
若满意,输出 i,标记 f[i]=1,并更新 b[i] += max(0, a[i-k]+b[i-k]-a[i]),这等价于 b[i] = b[i] + (finish_j - arr_i 如果为正),从而 a[i]+b[i] 成为新的结束时间。
题解c++98
#include<bits/stdc++.h>
using namespace std;
int n,a[1005],f[1005],b[1005],c[1005];
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i]>>b[i]>>c[i];
if(i==1)cout<<1<<'\n',f[1]=1;
else{
int k=1;
while(!f[i-k])k++;
if(f[i-k]){
if(a[i]+c[i]>=a[i-k]+b[i-k]){
cout<<i<<'\n';
f[i]=1;
b[i]+=max(0,a[i-k]+b[i-k]-a[i]);
}
}
}
}
return 0;
}
4 条评论
-
zhongjunnan LV 8 @ 2026-6-10 13:54:06
-
@ 2026-6-8 15:40:36
-
@ 2026-6-8 13:08:59
你怎么能搬题呢,陈建州?
-
@ 2026-6-6 23:38:30已置顶,不过格式好丑,希望下次可以调整一下格式
- 1