CSP-X复赛模拟四补题报告

本文概述了一场CSP-X复赛的模拟四题目,涉及四个编程题目:除法练习理解绝对值,买糖豆计算装满罐子数量,序列分块计算最大评分,以及射箭比赛策略优化体力消耗。作者分享了比赛过程中的思考与代码实现,强调了即使是简单题也要细心对待。
摘要由CSDN通过智能技术生成

                           CSP-X复赛模拟四补题报告
                                 时间:2023年10月12日
                                         S12004 张伯钧

一、分数:
        总分:50’
        T1【小可的除法练习】:0’
        T2【小可买糖豆】:10’
        T3【序列分块】:0’
        T4【射箭比赛】:40’

二、比赛过程:

第一题:

        题没读懂,绝对值的意思不理解,所以没写代码。

第二题:

        题读懂了,我以为能全对,但不过代码有亿点点问题。

第三题:

        压根儿没仔细看,瞎写了一个。

第四题:

        有点思路,但不多,发现方法时,没时间了。

三、比赛分析:

第一题:

小可的除法练习

时间限制:1秒        内存限制:128M

题目描述

小可学习了除法!然后达达为了难住小可,出了这么一个问题:

有n个整数a​1​​,a​2​​,⋯,a​n​​,需要找到一个绝对值最小的非0整数x,满足x/​​a​i​​​​>0的a​i​​的数量大于等于​2​/n​​向下取整。

如果存在绝对值相等的两个数都满足条件且绝对值最小, 输出正数。

如果不存在这样的数,输出0。

小可被难住啦!快来帮帮小可。

输入描述

第一行一个整数n,代表数字的数量。
第二行n个整数a​i​​

输出描述

如题,输出满足条件的x

样例输入

7
0 0 1 -1 0 0 2

样例输出

0

数据范围

对于20%的数据,n≤100

对于60%的数据,n≤10^​5​​

对于100%的数据,∣a​i​​∣≤10​^12​​,1≤n≤10^​6​​

思路:

        统计正数与负数的数量,如果整数的数量大于等于一半,那么输出1,如果负数的数量大于等于一半,那么输出-1,否则输出0。

代码实现:

#include<iomanip>
#include<iostream>
#include<cmath>
#include<string>
#include<cstring>
#include<algorithm>
#include<cstdio> 
#include<vector>
using namespace std;
long long x,cnt1,cnt2;
int main(){
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%lld",&x);
		if(x>0) cnt1++;//正数的数量
		if(x<0) cnt2++;//负数的数量
	}
	if(cnt1<n/2&&cnt2<n/2){
		printf("0"); 
	}
	else if(cnt1>=n/2){
		printf("1");
	}
	else printf("-1");
	return 0;
}

 第二题:

小可买糖豆

时间限制:1秒        内存限制:128M

题目描述

小可想要买好多好多糖豆!并且要用小可喜欢的小罐罐装!

只有装满了一个罐罐,小可才会用下一个罐罐。

小可进行了n次购买操作,每次购买操作结束之后,请你告诉小可,这次购买操作装满了多少个罐罐!

输入描述

第一行两个正整数,n,m,代表小可进行了n次购买操作,以及每个小罐罐最多能装多少个糖豆。

第二行n个整数1,2,⋯,a​1​​,a​2​​,⋯,a​n​​,代表小可这一次买了多少个糖豆。

输出描述

对于每次购买操作,都要输出有多少个小罐罐在这一次购买操作中被装满了。

样例输入

4 5
2 2 1 5

样例输出

0 0 1 1

数据范围

对于40%的数据,n≤1000

对于100%的数据,1≤a​i​​,m≤10^​9​​,1≤n≤10^​5​​

思路:

        每输入一个数计数器就+上这个数,然后输出计数器/m,再让计数器%m。

代码实现:

#include<iomanip>
#include<iostream>
#include<cmath>
#include<string>
#include<cstring>
#include<algorithm>
#include<cstdio> 
#include<vector>
using namespace std;
int main(){
	int n,a,m,c=0;
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>a;
		c+=a;
		cout<<c/m<<" ";//输出
		c%=m;
	}
	return 0;
}

第三题:

序列分块

时间限制:1秒        内存限制:128M

题目描述

小可手中有一个序列a,小可可以在序列a中选定一个区间[l,r],然后将这个区间分成单独的一块,其他不在块内的数字全部忽略不计。显然小可有许多分块方案。分块之后,小可还需要对这个分块计算出一个评分:

评分的计算规则如下:对于分块的这个区间[l,r],小可把这个区间划分成c个连续的小段,每段为 [l​1​​,r​1​​],[l​2​​,r​2​​],⋯,[l​c​​,r​c​​],并且这个区间中的每个数都属于其中一个小段,不存在一个数被多个小段包含的情况。这时候的评分为:

c+∑​i=1​c​​MEX(a[l​i​​],a[l​i​​+1],⋯,a[r​i​​])

其中 MEX(S) 为最小的没有出现在集合 S 中的非负整数。换句话说,如上评分的值为划分的段数加上每一段的 MEX 值。

小可想知道,所有的分块方案的最大评分的和是多少。

输入描述

第一行一个正整数t(1≤t≤30),代表有t组输入。

对于每组输入,第一行一个整数n(1≤n≤100),代表序列a的长度。
第二行n个整数a​i​​(0≤a​i​​≤10​9​​),代表序列a中的每个数字。

保证这t组输入的n的总和不会超过100。

输出描述

对于每组输入,输出一行一个整数,代表所有的分块方案的最大评分的和。

样例输入

4
2
1 2
3
2 0 1
4
2 0 5 1
5
0 1 1 0 1

样例输出

4
14
26
48

提示

对于第二组输入,

分块 [2,0,1] 的最佳划分: [2],[0,1] 。 评分为 2+mex(2)+mex(0,1)=2+0+2=4 。
分块 [2,0] 的最佳划分: [2],[0] 。评分为 2+mex(2)+mex(0)=2+0+1=3。
分块 [2]的最佳划分 :[2] 。 评分为 1+mex(2)=1+0=1 。
分块 [0,1] 的最佳划分: [0,1] 。 评分为 1+mex(0,1)=1+2=3 。
分块 [0] 的最佳划分: [0] 。 评分为 1+mex(0)=1+1=2 。
分块 [1] 的最佳划分: [1] 。 评分为 1+mex(1)=1+0=1 。

所有分块方案的最大评分和为 4+3+1+3+2+1=14 。

对于40%的数据,t=1,n<=10

对于100%的数据,1≤t≤30,1≤n≤100

思路:

        3个循环找区间,如果为0再加一。

代码实现:

#include<iomanip>
#include<iostream>
#include<cmath>
#include<string>
#include<cstring>
#include<algorithm>
#include<cstdio> 
#include<vector>
using namespace std;
int a[105];
int main(){
	int t,n; 
	cin>>t;
	while(t--){
		cin>>n;
		for(int i=1;i<=n;i++){
			cin>>a[i];
		}
		int ans=0;
		for(int i=1;i<=n;i++){
			for(int j=i;j<=n;j++){
				for(int k=i;k<=j;k++){
					ans++;
					if(a[k]==0) ans++;
				}
			}
		}
		cout<<ans<<endl;
	} 
	return 0;
}

第四题:

射箭比赛

时间限制:1秒        内存限制:128M

题目描述

小可参加了一个射箭比赛。这个比赛有n个靶子,第i个靶子的位置为x​i​​。小可最开始的位置为0。

小可可以做如下操作,可以认为靶子被射中之后会消失:

  • 选择一个已经射中的靶子,小可的位置可以移动到这个靶子的位置上。假设小可和这个靶子的距离为c,那么这次移动需要消耗的体力为a×c。

  • 选择一个没有被射中的靶子,同时小可和这个靶子之间不能有其他未被射中的靶子。小可一定会射中。假设小可和这个靶子的距离为c,这个操作消耗的体力为b×c。

为了节省体力,小可想知道射完所有的靶子,所消耗的体力总和最小是多少。

输入描述

第一行一个正整数t(1≤t≤10​3​​),代表有t组输入。

对于每组输入,第一行三个正整数n,a,b(1≤n≤2×10​5​​,1≤a,b≤10​5​​)。
第二行n个整数x​1​​,x​2​​,⋯,x​n​​(1≤x​i​​≤10​8​​),代表每个靶子的位置。保证靶子的位置是单调递增的。

输出描述

对于每组输入,如题,输出答案。

样例输入

4
5 2 7
3 5 12 13 21
5 6 3
1 5 6 21 30
2 9 3
10 15
11 27182 31415
16 18 33 98 874 989 4848 20458 34365 38117 72030

样例输出

173
171
75
3298918744

提示

对于20%的数据,t=1,1≤n≤10。
对于60%的数据,1≤t≤10,1≤n≤100。
对于100%的数据。1≤t≤10​^3​​,1≤n≤2×10^​5​​,保证t组输入的n的和不会超过2×10​5​​。

思路:

        每射一次箭,就判断到底是不动好,还是动一动(当中需要一个前缀和数组)。

代码实现:

#include<iomanip>
#include<iostream>
#include<cmath>
#include<string>
#include<cstring>
#include<algorithm>
#include<cstdio> 
#include<vector>
using namespace std;
int sum[200005]={0};
int main(){
	long long t,n,a,b,x[200005];
	cin>>t;
	while(t--){
		long long xk=0,ans=0;
		cin>>n>>a>>b;
		for(int i=1;i<=n;i++){
			scanf("%lld",&x[i]);
			sum[i]=sum[i-1]+x[i];//求解距离前缀和数组 
		}
		for(int i=1;i<=n;i++){
			ans+=(x[i]-xk)*b;//xk目前所处位置为上一轮计算过的最优位置 
			long long ans1=(sum[n]-sum[i]-(n-i)*xk)*b;//若不动 
			long long ans2=(x[i]-xk)*a+(sum[n]-sum[i]-x[i]*(n-i))*b;//若移动 
			if(ans2<ans1){
				ans+=(x[i]-xk)*a;
				xk=x[i];
			}
			
		}
		printf("%lld\n",ans);
	}
	return 0;
}

四、总结

        简单的题,不要因为简单而不重视,要多检查。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
CSP-J复赛历年试题pdf是指CSP-J的复赛历年试题的PDF文件。CSP-J是中国计算机学会(CCF)主办的一项高中生计算机科学与编程的竞赛。复赛CSP-J竞赛的第二个阶段,参赛者需要通过初赛选拔才能进入复赛CSP-J复赛历年试题pdf中包含了以往CSP-J复赛的试题和答案。这些试题主要涵盖了计算机科学与编程的各个方面,包括编程语言、算法、数据结构、计算机网络等。参赛者可以通过研究历年试题,了解CSP-J竞赛的题型和出题风格,提高自己的解题能力和编程水平。 CSP-J复赛历年试题pdf对于参赛者来说具有很大的参考价值。通过研究这些试题,参赛者可以了解到高水平的计算机科学与编程问题是如何被设计和解决的。同时,参赛者还可以通过尝试解答这些试题,检验自己的知识和技能,发现自己的不足之处并进行改进。 此外,CSP-J复赛历年试题pdf还对教师和学生进行教学和学习有很大的帮助。教师可以利用这些试题作为教学资源,丰富教学内容和方法,提高学生的计算机科学与编程能力。学生可以通过研究这些试题,扩展知识面,提升解决问题和编程的能力。 总之,CSP-J复赛历年试题pdf是一份重要的学习和竞赛资料,对参赛者、教师和学生都具有很大的参考和帮助作用。通过研究这些试题,大家可以更好地了解计算机科学与编程的相关知识和技能,并提升自己的竞赛和学习能力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值