NKOJ考试2330-0520欢乐赛 总结+题解+分析

考试概览

题号名称
A方块消消乐
B相同的整数
C数列+1
D涂颜色
E外卖店
F外面路程
项目内容
说明阶段性小练习
类别日常作业题目列表
考试规则信息学奥赛规则
开始时间2023/5/20 14:10:00
结束时间2023/5/20 16:10:00
总时长2小时
参考人数共 43 人进入, 40 人提交
提交限制每题不超过 10 次

总结+吐槽

第一次线下课,老师何必行此大礼……
题目难度还行,E、F不会。
考了第三名,拿到了老师的奶茶
第一次限制提交次数,总感觉次数会用完。不过并没有。

A题:刚开始用的模拟,TLE了4个点,后来想出新思路,终于AC了。
B题:真的很简单。
C题:刚开始感觉这道题是自己不擅长的类型,感觉做不出来,写着写着感觉和B好像,然后AC了。
D题:刚开始没读懂题,想到了模拟、骗分,最后想出正解,AC了。我同桌还好奇我是怎么骗到AC的
E题:感觉和P5224很像,但网课摸鱼(羞),不会,骗了10分。后来发现这其实是 摄像头1模型
F题:不出意外的不会,1分都没骗着: (。


题解

A题:方块消消乐

问题描述

何老板在玩一款消消乐游戏,游戏虽然简单,何老板仍旧乐此不疲。
游戏一开始有n个边长为1的方块叠成一个高为n的柱子。
有红色和蓝色两种方块。
游戏操作:玩家选择两个相邻且不同色的方块,将它们消除。然后上方的方块会自动落下来,使得剩下的方块始终保持柱状。

玩家可以进行任意次上述操作,消除的方块越多,得分越高。何老板想知道:最多能消除掉多少方块?

输入格式

一个由0和1构成的字符串,表示游戏开始时的方块柱子。其中0表示蓝色方块,1表示红色方块。

输出格式

一个整数,表示最多能消除的方块数。

样例

样例输入 1
0011
样例输出 1
4
样例输入 2
11011010001011
样例输出 2
12
样例输入 3
0
样例输出 3
0

提示

设字符串的长度为n:
1 ≤ n ≤ 1 0 5 1\le n\le 10^5 1n105

思路及代码

本题我用的是stringchar字符组也行。
输入就难倒了一大片英雄汉。
在不知道总长度的情况下,怎么输入字符串?
很明显,cin>>嘛!看到有人还在用forwhile,我震惊了。
我的第一种思路:模拟
每当找到可以消除的方块对时,消除它们两个,把后面的往前移。
往前移的块数越少,速度越快,因此应从后往前搜索。
72分代码:

#include<bits/stdc++.h>
using namespace std;
string a;
int main(){
	int n = 0,ans = 0;
	bool flog = 1;//flog用于检测本次循环是否消除方块,若没有可消除的,就不循环了。
	cin>>a;
	n = a.size();
	while(flog){
		flog = 0;
		for(int i = n-1; i >= 0; i--){
			if((a[i] == '1' && a[i-1] == '0') || (a[i] == '0' && a[i-1] == '1')){
				ans += 2;
				a.erase(i-1,2);
				n -= 2;
				flog = 1;
				break;
			}
		}
	}
	printf("%d",ans);
	return 0;
}

但——

看来模拟不是正解。
还有一种方法,就是统计红块和蓝块的个数,选择较少的一个颜色,把它们全部消除。答案就是它们的总数 × 2 \times 2 ×2
AC代码:

#include<bits/stdc++.h>
using namespace std;
string a;
int main(){
	int n = 0,b = 0,r = 0;
	cin>>a;
	n = a.size();
	for(int i = 0; i < n; i++){
		if(a[i] == '1'){
			r++;
		}else{
			b++;
		}
	}
	if(r > b){
		printf("%d",b*2);
	}else{
		printf("%d",r*2);
	}
	return 0;
}

B题:相同的整数

问题描述

有三个整数 A A A B B B C C C,有以下两种操作可供你选择:

A A A B B B C C C中任选两个数,使它们都增加 1 1 1
A A A B B B C C C中任选一个数,使它增加 2 2 2
请问如果想让 A A A B B B C C C都相等,最小需要操作几次。

输入格式

第一行,三个空格间隔的整数 A A A B B B C C C

  • 0 ≤ A , B , C ≤ 50 0\le A,B,C\le 50 0A,B,C50
  • A A A B B B C C C均为整数。

输出格式

一个整数,表示最小需要操作的次数。

样例

样例输入 1
2 5 4
样例输出 1
2
样例输入 2
2 6 3
样例输出 2
5
样例输入 3
31 41 5
样例输出 3
23

提示

样例一:

  • 第一步,将 2 2 2 4 4 4都增加1,得到 3 3 3 5 5 5 5 5 5
  • 第二步,将 3 3 3增加 2 2 2,得到 5 5 5 5 5 5 5 5 5

思路及代码

我们先将3个数从小到大排序;
接下来算出第1、2个数与最大的数的差距总和。
接下来分情况讨论:

  • 如果这个差距总和是偶数,那么不管用哪种操作,差距总和都会减2。总操作数为差距总和 ÷ 2 \div 2 ÷2
  • 如果这个差距总和是奇数,我们可以将最大数和另一个数分别加1,剩下的那个数不变。差距总和加1,变为偶数。接下来按情况1操作。
    AC代码:
#include<bits/stdc++.h>
using namespace std;
int a[3];
int main(){
	int x,y;
	for(int i = 0; i < 3; i++){
		scanf("%d",&a[i]);
	}
	sort(a,a+3);
	x = a[2]-a[0];
	y = a[2]-a[1];
	if((x-y)%2 == 1){
		printf("%d",(x+y+1)/2+1);
	}else{
		printf("%d",(x+y)/2);
	}
	return 0;
}

C题:数列+1

问题描述

给n个整数,每次操作可以将⼀个数+1,要使这n个数都不相同, 求⾄少要加多少次?

n<=10000 给出的数字数值在[-10000,10000]

输入格式

第一行,一个整数n
第二行,n个空格间隔的整数

输出格式

一个整数,表示最少需要操作的次数

样例

样例输入 1
4
1 3 1 4
样例输出 1
1
样例输入 2
5
1 2 3 2 5
样例输出 2
2

思路及代码

我用的是桶排序的思想。
已知给出的数字数值在[-10000,10000]之间,一共20001个数。
每输入一个数,就看看该位置有没有数。如果有数,就不停+1直到到达没有数的位置。
AC代码:

#include<bits/stdc++.h>
using namespace std;
int a[20001];
int main(){
	int n,tp,ans = 0;
	scanf("%d",&n);
	for(int i = 0; i < n; i++){
		scanf("%d",&tp);
		a[tp+10000]++;
		if(a[tp+10000] >= 2){
			for(int i = tp+10000; a[i] >= 2; i++){
				ans++;
				a[i] -= 1;
				a[i+1]++;
			}
		}
	}
	printf("%d",ans);
	return 0;
}

D题:涂颜色

问题描述

有n堆石头,第i堆的石头数量为Ai。
何老板有k种颜色的颜料,他安排你给所有石头都涂上颜色。
何老板还给你提出一个额外的要求:任意两堆石头中,颜色相同的石头的数量之差不能超过1。
在涂色前,你需要先回答何老板是否存在满足上述条件的方案,能输出“YES”,否则输出“NO”

输入格式

第一行,一个整数t,表示有t组测试数据,对于每组数据:
第一行,两个整数n和k
第二行,n个空格间隔的整数,依次表示每堆石头的数量

输出格式

有解输出YES,无解输出NO

样例

样例输入
3
4 4
1 2 3 4
5 2
3 2 4 1 3
5 4
3 2 4 3 5
样例输出
YES
NO
YES

提示

第3组数据说明:
5堆石头中每颗石头涂色方案如下:
第1堆:1 2 3
第2堆:1 3
第3堆:1 2 3 4
第4堆:1 3 4
第5堆:1 1 2 3 4

数据范围:
1 ≤ t ≤ 10
1 ≤ n, k ≤ 100
1 ≤ 每堆石头数量 ≤ 100

思路及代码

先排序,找到最少的石头堆,设这堆石头有 x x x个。
将每堆石头前 x x x个涂上相同的颜色。
剩下的石头每一个涂一种颜色(如图):

这下就好办了。我们只需要算出最大的石头与最小的石头之差,看这个差是否大于颜料总数即可。
AC代码:

#include<bits/stdc++.h>
using namespace std;
int a[120];
int main(){
	int t,n,k;
	scanf("%d",&t);
	for(int q = 0; q < t; q++){
		scanf("%d%d",&n,&k);
		memset(a,0,120);//清零
		for(int i = 0; i < n; i++){
			scanf("%d",&a[i]);
		}
		sort(a,a+n);
		if(a[n-1]-a[0] <= k){
			printf("YES\n");
		}else{
			printf("NO\n");
		}
	}
	return 0;
}

E题:外卖店

问题描述

有一条笔直公路,何老板打算在公路旁开若干间快餐店,以便为沿路的 n n n个小区提供外卖服务。

有个 n n n小区,全部分布在公路的同一侧。为保证送餐速度以及用餐品质,何老板规定,外卖店送餐的直线距离不能超过 d d d米。
现在已知每个小区的位置,问,最少开设多少间快餐店,就能给所有小区提供外卖服务。 若无法给所有 n n n个小区都送餐,输出 − 1 -1 1

具体而言,如下图所示,给出一个坐标轴,其中 x x x轴表示笔直公路,何老板的快餐店都将开设在 x x x轴上。
所有的小区都分布在 x x x轴上方(即 y y y轴的正半轴)。每个外卖店服务的半径为 d d d,问最少需要多少间外卖店。
Alt

输入格式

第一行,两个整数 n n n d d d
接下来 n n n行,每行两个整数 x x x, y y y,表示一个小区的坐标

输出格式

一行,一个整数,表示最少所需外卖店数量。无解输出" − 1 -1 1"

样例

样例输入 1
3 2
1 2
-3 1
2 1
样例输出 1
2
样例输入 2
8 5
2 4
-4 4
-3 3
-3 1
-3 0
-1 0
0 5
6 0
样例输出 2
3

提示

1 ≤ n ≤ 50000 1\le n\le 50000 1n50000
1 ≤ d ≤ 50000 1\le d\le 50000 1d50000
− 50000 ≤ x , y ≤ 50000 -50000\le x,y\le 50000 50000x,y50000
样例1解释:如题图所示

思路及代码

思路:这本质上是摄像头1模型。如何将每个外卖店转换成线段呢?很简单。

对于每个外卖店,我们知道它的 y y y坐标和最远距离 d d d。那么我们求得 f f f d 2 − y 2 \sqrt{d^2-y^2} d2y2
那么此时端点 a a a就是 x − f x-f xf,端点 b b b x + f x+f x+f。于是乎,这道题就变成了标准的摄像头1模型。
注意判定无解情况,即 y > d y > d y>d
AC代码:

#include<bits/stdc++.h>
using namespace std;
struct xiaoqu{
	int x,y;
	double a,b;
}x[50005];
bool cmp(xiaoqu a,xiaoqu b){
	return a.b < b.b;
}
int main(){
	int n,d,first = 0,ans = 1;
	double f;
	bool go_on = 1;
	scanf("%d%d",&n,&d);
	for(int i = 0; i < n; i++){
		scanf("%d%d",&x[i].x,&x[i].y);
		if(x[i].y > d){
			printf("-1");
			go_on = 0;
			break;
		}else{
			f = sqrt((d*d) - (x[i].y*x[i].y));
			x[i].a = x[i].x-f;
			x[i].b = x[i].x+f;
		}
	}
	if(go_on){
		sort(x,x+n,cmp);
		for(int i = 0; i < n; i++){
			if(x[first].b < x[i].a){
				ans++;
				first = i;
			}
		}
		printf("%d",ans);
	}
	return 0;
}

F题:外卖路程

问题描述

何老板下班回家,他骑着一辆自行车,学校到家的为一条直路,距离为M公里。学校在0公里处,家在M公里处。

沿途每个一公里,都有一个小区。小区间有大量的外卖业务。何老板打算在回家途中,顺便揽送一些送外卖,赚点钱,补贴家用。

今天,何老板揽了N个送外卖业务,其中第i号业务用两个整数 a i , b i a_i,b_i ai,bi来表示,何老板需要在第 a i a_i ai公里处的小区去取外卖,送到 b i b_i bi公里处的小区。

何老板的自行车上有个足够大的货框,能装下所有外卖。问,送完所有外卖,最后回到家,何老板行驶的最短总路程是多少?请你帮忙计算!

输入格式

第一行,两个整数n和m
接下来n行,每行两个整数,表示一单业务的起点和终点

输出格式

一个整数,表示最小总距离

样例

样例输入 1
2 10
2 8
6 4
样例输出 1
14
样例输入 2
8 15
1 12
3 1
3 9
4 2
7 13
12 11
14 11
14 13
样例输出 2
27

提示

对于40%的数据, n ≤ 5000 n\le 5000 n5000
对于50%的数据, n ≤ 200000 n\le 200000 n200000
对于100%的数据, n ≤ 300000 n\le 300000 n300000 3 ≤ m ≤ 1 0 9 3\le m\le 10^9 3m109

思路及代码

总路程分为两段:

  • 回家固定的路程: m m m
  • 额外的路程:送外卖的部分。

对于每一个订单:

  • a < b a<b a<b则顺路,不需要额外的往返路程;
  • a > b a>b a>b则不顺路,需要额外的往返路程。


AC代码:

#include<bits/stdc++.h>
using namespace std;
struct xiaoqu{
	int a,b;
}a[3000005];
inline bool operator < (xiaoqu a,xiaoqu b){
	return a.b < b.b;
}
int main(){
	int n,m,l = 0,r = 0;
	long long int ans;
	scanf("%d%d",&n,&m);
	ans = m;
	for(int i = 0; i < n; i++){
		scanf("%d%d",&a[i].a,&a[i].b);	
	}
	sort(a,a+n);
	for(int i = 0; i < n; i++){
		if(a[i].a <= a[i].b){
			continue;
		}
		if(a[i].b > r){
			ans += 2*(r-l);
			l = a[i].b;
		}
		r = max(r,a[i].a);
	}
	ans += 2*(r-l);
	printf("%lld ",ans);
	return 0;
}

记得三连。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据引用\[1\]和引用\[3\]的信息,我们可以得知顿顿需要在n天间内完成m项科目的加强训练。每项科目有一个编号,编号为i,其中1≤i≤m。每项科目的训练间为ti天,即从第a天开始训练科目i,训练将持续到第a+ti−1天。科目之间存在依赖关系,如果科目i依赖科目j,那么只能在科目j训练结束后,科目i才能开始训练。 对于csp202212-2题目中的c++训练计划,我们需要知道c++训练的编号以及训练的间。根据题目描述,我们可以得知c++训练的编号为2。然而,题目中没有提供c++训练的具体间。因此,我们无法确定c++训练的间。 综上所述,我们无法确定c++训练的具体计划。 #### 引用[.reference_title] - *1* *3* [CCF CSP 202212-2 训练计划(C++)](https://blog.csdn.net/qq_46092061/article/details/129207826)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [CCF-CSP真题《202212-2 训练计划》思路+python题解](https://blog.csdn.net/weixin_53919192/article/details/129084465)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值