• 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 条评论

  • 1