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

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

一、分数:
        总分:60’
        T1【项链】:0’
        T2【扫地机器人】:0’
        T3【二进制魔法】:0’
        T4【寄居蟹】:60’

二、比赛过程:

第一题:

        考试时不知道咋想的,认为数据范围超出了数组的范围,所以没用数组,要不然就可能全对了。【ㄟ( ▔, ▔ )ㄏ】

第二题:

        稍微找到了点规律,当时以为这题稳了,后来发现还是思路上有问题。

第三题:

        当时想着要骗点分,但我也不知道为啥没骗到。

第四题:

        这道题我压根儿没抱什么希望,瞎写了个不确定代码,没想到拿了60分!!!【w(゚Д゚)w】

三、比赛分析:

第一题:

项链

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

题目描述

小可现在手里有好多亮闪闪的小球,于是小可打算选择一些小球串成项链。但是,小可还不会怎么把项链首尾相接成环,所以小可只是打算暂时将这些小球串成一条链。

每种小球有一个愉悦值,但是如果一种小球连续出现D个,就会产生审美疲劳。每种小球的数量都可以认为是无限的。

请问,用m个小球串成一条链,总的愉悦值最大是多少?

注意:这里的链不成环,首位不相接,第一个小球和最后一个小球不相邻。

输入描述

第一行三个整数n,m,D,分别代表小球的种类数,需要用到的小球数,D的含义如题。

第二行n个整数a​1​​,a​2​​,⋯,a​n​​(1≤a​i​​≤10​9​​) ,代表第i种小球的愉悦值是多少。

输出描述

输出一个正整数,代表总的愉悦值最大是多少。

样例输入

3 5 2
3 4 5

样例输出

23

数据范围

对于20%的数据,m≤1000
对于60%的数据,n≤10^​5​​
对于100%的数据,1≤n≤10​^6​​,1≤m,D≤10​^9​​

思路:

        用数组,先sort一下,然后找出最大值和第二大值,最后稍微计算一下输出就行了。

        计算的思路大概是这样的:要想让愉悦值最大,而且一个珠子不能重复D次,先串D-1个愉悦值最大的珠子,然后再串一个愉悦值第二大的珠子,重复这个步骤,直到串完m个珠子。

代码实现:

#include<iomanip>
#include<iostream>
#include<cmath>
#include<string>
#include<cstring>
#include<algorithm>
#include<cstdio> 
#include<vector>
#include<stack>
#include<map>
#include<queue>
#define ll long long	
using namespace std;
ll a[1000005];
int main(){
	ll n,m,d,max,max2,ans=0;
	cin>>n>>m>>d;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	sort(a+1,a+n+1);//排序
	max=a[n];//最大值
	max2=a[n-1];//第二大值
	ans=(m/d)*(max*(d-1)+max2)+(m%d)*max;//公式
	cout<<ans;
	return 0;
}

第二题:

扫地机器人

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

题目描述

数轴上有一个扫地机器人,每次会到某个正整数的位置上打扫垃圾,然后回到坐标为00的位置。

每次出现垃圾,机器人必须前往这个坐标清理垃圾,然后回到坐标00。机器人不能清理沿途的其他垃圾。并且,如果一个坐标会出现x次垃圾,那么机器人必定会前往这个坐标x次。

小可统计了一些坐标会出现垃圾的次数。小可可以将这些出现次数分配到一些坐标上。请问,机器人需要经过的距离最小是多少?

垃圾出现的坐标可以是正整数或者负整数,垃圾不会在坐标0出现。但是我们在保证总距离最小的前提下,尽量少往负坐标走。

输入描述

第一行一个数字n

第二行n个整数a​1​​,a​2​​,⋯,a​n​​,表示某个坐标会出现a​i​​次垃圾。

输出描述

第一行一个整数,代表机器需要经过的总距离的最小值。

第二行n个整数。第i个数字代表了出现了a​i​​次垃圾的坐标。

样例输入

5
1 4 5 2 0

样例输出

30
-2 -1 1 2 3

数据范围

对于50%的数据,n≤100,a​i​​≤100
对于100%的数据,n≤2×10^​5​​,a​i​​≤10^​6​​,a​i​​两两不同,保证答案唯一。

思路:

        用结构体(为了后面按顺序输出),排序,遍历分情况判断,每次一个正坐标,一个负坐标交替着存。

代码实现:

#include<iomanip>
#include<iostream>
#include<cmath>
#include<string>
#include<cstring>
#include<algorithm>
#include<cstdio> 
#include<vector>
#include<stack>
#include<map>
#include<queue>
#define ll long long	
using namespace std;
struct node{
	int id;
	int data;
}a[200005];
bool cmp(node a,node b){
	return a.data>b.data;
}
bool cmp1(node a,node b){
	return a.id<b.id;
}
int main(){
	int n;
	cin>>n;
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i].data);
		a[i].id=i;
	}
	sort(a+1,a+n+1,cmp);
	ll sum=0,cnt=0;
	for(int i=1;i<=n;i++){
		if(i%2==1){//正数
			++cnt;
			sum+=2*cnt*a[i].data;//来回两趟
			a[i].data=cnt;
		}
		else{//负数
			sum+=2*cnt*a[i].data;//来回两趟
			a[i].data=-cnt;
		}
	}
	cout<<sum<<endl;
	sort(a+1,a+n+1,cmp1);
	for(int i=1;i<=n;i++){
		printf("%d ",a[i].data);
	}
	return 0;
}

第三题:

二进制魔法

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

题目描述

小可现在有两个二进制串S和T,现在小可施展了魔法,想把S变成T。对S可以做两种操作:

1、交换S​i​​和S​j​​,消耗的魔力值是∣i−j∣
2、对S​i​​取反,消耗的魔力值是11

请问将S变成T,小可消耗的魔力值最小是多少?

输入描述

第一行一个整数n,代表这两个二进制串的长度。

第二行和第三行分别一个二进制串,表示S和T。

输出描述

一个整数,代表小可消耗的魔力值的最小值是多少。

样例输入1

2
1
10

样例输出1

1

样例输入2

3
011
100

样例输出2

2

数据范围

对于20%的数据,n≤20
对于另外20%的数据,S,T之间最多有两个位置不同。
对于60%的数据,n≤10^​5​​
对于100%的数据,1≤n≤10^​6​​

思路:

        遍历,判断不一样的地方是交换合适,还是取反合适。

代码实现:

#include<iomanip>
#include<iostream>
#include<cmath>
#include<string>
#include<cstring>
#include<algorithm>
#include<cstdio> 
#include<vector>
#include<stack>
#include<map>
#include<queue>
#define ll long long
using namespace std;
int main(){
	int n;
	string s,t;
	cin>>n;
	cin>>s>>t;
	int cnt=0;
	for(int i=0;i<n;i++){
	//相邻不一样 且和t对应不相等 交换(1次)比修改(2次) 效率高
		if(s[i]!=t[i]&&s[i+1]!=t[i+1]&&s[i]!=s[i+1]){
			cnt++;
			swap(s[i],s[i+1]);
		}
		else if(s[i]!=t[i]){
			cnt++;
			if(s[i]=='0') s[i]='1';//可加可不加 
			else s[i]='0';//可加可不加 
		}
	}
	cout<<cnt;
	return 0;
}

第四题:

寄居蟹

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

题目描述

寄居蟹喜欢居住在螺壳中。小可养了许多寄居蟹,于是小可打算给每个寄居蟹准备一个小的螺壳和一个大的螺壳。

小可认为,一个大小为x的螺壳,必须和一个大小为k×x的螺壳在一起,才能给一个寄居蟹使用。

现在给定了n个螺壳的大小,请问按照上述规则匹配之后,最少剩下多少未匹配的螺壳?

输入描述

多组输入。第一行一个正整数t表示数据组数。

每组数据第一行两个正整数表示 n 和 k。

第二行n个正整数表示每个螺壳的大小。

输出描述

每组数据输出一个整数,代表最少剩余多少个螺壳未匹配。

样例输入

4
1 7
1
2 2
1 2
3 2
1 2 4
4 3
1 3 9 27

样例输出

1
0
1
0

数据范围

对于20%的数据,n=1

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

对于100%的数据,1≤k≤10^​9​​,∑n≤5×10​^5​​。每个螺壳的大小不超过10​9​​。

思路:

        非常复杂,要用map,我先讲一下我的做法(我这道题是蒙的,我也不知道为什么得了60):

        遍历数组,判断a[i]是否等于-1,如果不是,从i+1开始遍历。如果a[i]*k==a[j]&&a[j]!=-1那么把他们都变成-1,然后break。

        最后输出a[i]为-1的个数。

代码实现(60):

#include<iomanip>
#include<iostream>
#include<cmath>
#include<string>
#include<cstring>
#include<algorithm>
#include<cstdio> 
#include<vector>
#include<stack>
#include<map>
#include<queue>
#define ll long long
using namespace std;
int a[500005]; 
int main(){
	freopen("hermit.in","r",stdin);
	freopen("hermit.out","w",stdout);
	int t,n,k;
	cin>>t;
	while(t--){
		cin>>n>>k;
		for(int i=1;i<=n;i++){
			cin>>a[i];
		}
		sort(a+1,a+n+1);
		for(int i=1;i<=n;i++){
			if(a[i]!=-1){
				for(int j=i+1;j<=n;j++){
					if(a[i]*k==a[j]&&a[j]!=-1){
						a[i]=-1;
						a[j]=-1;
						break; 
					}
				}
			}
			
		}
		int c=0;
		for(int i=1;i<=n;i++){
			if(a[i]!=-1){
				c++;
			}
		}
		cout<<c<<endl;
	}
	fclose(stdin);
	fclose(stdout);
	return 0;
}

代码实现(100):

#include<iomanip>
#include<iostream>
#include<cmath>
#include<string>
#include<cstring>
#include<algorithm>
#include<cstdio> 
#include<vector>
#include<stack>
#include<map>
#include<queue>
#define ll long long
using namespace std;
const int N=5e5+10;
ll a[N];
map<ll,int>mp;
int main(){
	ll t,n,k;
	scanf("%lld",&t);//cin>>t;
	while(t--){
		scanf("%lld%lld",&n,&k);//cin>>n>>k;
		for(int i=1;i<=n;i++){
			scanf("%lld",&a[i]);
			mp[a[i]]++;
		}
		sort(a+1,a+n+1);
		for(int i=1;i<=n;i++){
			if(k==1){
				if(mp[a[i]]>1){
					mp[a[i]]-=2;
				}
			}
			else if(mp[a[i]]>=1&&mp[a[i]*k]>=1){//mp.count(a[i]*k)
				mp[a[i]*k]--;
				mp[a[i]]--;
			}
		}
		ll cnt=0;
		map<ll,int>::iterator it;
		for(it=mp.begin();it!=mp.end();it++){
			if(it->second>=1){
				cnt+=it->second;
			}
		}
		printf("%lld\n",cnt);
		mp.clear();
	}
	return 0;
}

总结:

        多找规律(前两题)多想想,最后一题其实很容易拿分。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 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、付费专栏及课程。

余额充值