2024Coduck csp-x复赛模拟1补题报告

 学号:S11503,姓名:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

谁家玉笛暗飞声,我要*****

啊,又是一个美好的国庆节。but,Coduck吞了我5天假期,这么算下来七天假期-两天补课-周六周天-五天复赛急训=倒赔两天假!!!!!!!!!!!!!!!!!!!!!可恶的Coduck还我假期!(写这句话的时候被老师锤了一下……)

第一次参加复赛模拟考怎么说呢,没有爆0就是胜利好吧。(出自一位同学的补题报告)

题目一《做饭》cook

题目描述:小可对达达真的是真爱!小可为了体现对达达的爱,特意要为即将下班的达达做一顿丰富的晚饭!已知达达到家时间是 K 时刻,并且知道当前处在 now 时刻。小可需要 p 秒时间去准备好饭菜。假设小可制作晚饭总共需要 q 秒时间。请问赶在达达到家之前,小可是否能准备完晚饭。

输入格式

输入第一行按照 hh : mm : ss,即时:分:秒表示的时间 now,表示当前时间。

输入第二行按照 hh : mm : ss,即时:分:秒表示的时间 K,表示达达到家的时刻。

输入第三行两个整数p,q,分别表示准备时间和制作时间。

输出格式

如果可以赶在达达回家之前制作完晚饭,输出Yes,否则输出No

输入样例1
11:45:14
19:19:0
114 514
输出样例1
Yes
输入样例2
11:45:14
11:56:0
1145 14
输出样例2
No
提示

输入的 K 和 now 使用距离某个时刻之后的时分秒记录,可能不符合现实中的时间记录。

时间是24小时进制,时间的计算方式与现实生活中相同。

数据描述

使用 hh,min,ss 分别表示输入时刻中的时、分、秒。

对于 40% 的数据:0≤ℎℎ≤23,≤59,0≤10000≤hh≤23,0≤min,ss≤59,0≤p,q≤1000。

对于 100% 的数据:0≤ℎℎ,≤106,0≤10^8,0≤hh,min,ss≤10​^6​​,0≤p,q≤10​^8​​。

这个题我想的思路是全部转换成为秒种,即累加器时间=秒钟+分钟*60+小时*3600,把起始时间与结束时间全部求出来,相减得出来的数再减去准备食材的时间减去做饭用的时间,还需要注意一下,里面说了是在达达回来之前做完,so需要判断>0。除此之外还需要注意数据的大小,因此要用long long 兄。

以下是AC代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
using namespace std;
int main(){
	//freopen("cook.in","r",stdin);
	//freopen("cook.out","w",stdout);
	long long  xs,fz,mz,zhunbei,zuofan;//定义变量不多说了
	scanf("%lld:%lld:%lld",&xs,&fz,&mz);//用scanf输入时分秒,输入格式说了需要用冒号表示,并且注意时分秒使用long long 表示,所用需要%lld,这个问题用dev是查不出来的需要注意
	long long  sj=mz;//表示的第一处起点时间转化为秒
	sj+=fz*60;//分钟化秒
	sj+=xs*3600;//小时化秒
	scanf("%lld:%lld:%lld",&xs,&fz,&mz);//输入同上
	long long  sj2=mz;//此处表示是终点时间
	sj2+=fz*60;
	sj2+=xs*3600;
	sj2-=sj;
	scanf("%d%d",&zhunbei,&zuofan);//此处是表示小可的准备饭菜时间和做饭时间
	if((sj2-zhunbei-zuofan)>0) cout<<"Yes";//判断,如果间隔时间减去准备和做饭的时间大于0,即在达达回来之前做完的,输出Yes,首字母大写,我一个同学就是因为这个错的
	else cout<<"No";//同上同上
	//fclose(stdin);
	//fclose(stdout);
	return 0;//华丽结束~~~~~~~~~
} 

注:因为是复赛,所以要加上freopen和fclose

作者自述:这个题错的原因纯粹是数组开的不够大,得91分

第二题《评价标准》criterion

问题描述

给定一个长度为 n 的数组 S ,其中包含1,2,⋯,S​1​​,S​2​​,⋯,S​n​​。

定义数组 S 的评价标准为:最大值-最小值

小可同学觉得问题过于简单。然后定义了一种操作:给定一个操作值 k,然后任意从数组中选择一个数字x,可以将数字 x 加上k,或者减去 k,之后得到一个新的数组,并使得新数组的评价标准最小。最终输出最小的评价标准。

输入格式

输入第一行包含两个整数 ,n,k 。

第二行输入数组 S,总共 n 个整数,使用空格分开。

输出格式

输出一行,包含一个整数,表示操作后最小的评价标准。

输入样例
5 114
19 19 810 114 514
输出样例
677
数据描述

对于 40% 的数据:2≤100,0≤10002≤n≤100,0≤S​i​​,k≤1000

对于 100%100% 的数据:2≤106,0≤1082≤n≤10​6​​,0≤∣S​i​​∣,∣k∣≤10​8​​。

老师讲这一道题的时候我们被阴险的老师狠狠地坑了一波……

思考一下下,这道题有k,有max和min,为了一会便于思考在增加一个cmax和cmin,这两个是次大和次小。可以-k也可以+k,为了让max-min的差值是最小的,那么只能是小的数加上k,大的数减去k。min+k有几种可能?max-k又有几种可能?把这些可能写出来这道题就做完了。min+k第一种可能就是依旧是最小值,第二种可能就是比原先的次小大了但是没有超过max,这时候cmin就变成了min,第三种可能直接变成了max最大值(小剧情:皇帝对一个难民说:“你是我失散多年的亲儿子,以后你回东宫当太子”)。max-k的可能性其实是差不多的,第一种可能就是依旧是最大值,第二种可能就是比次大要小,但还是比min要大,第三种可能就是直接变成了最小值min(小剧情:皇帝对太子说:“你不是我的儿子,你走吧不要再回来了”)。

最后将这几种可能全部算出来,选出最小的值输出。

AC代码:

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
typedef long long ll;
const int N=1e6+10,M=0x3f3f3f3f;//常量不说了
int maxx=-M,cmax=-M,minn=M,cmin=M;//最大值最小值,次大值次小值
int n,k,s[N];
int ans;
int main(){
	cin>>n>>k;
	k=abs(k);//有正负,直接取K的绝对值
	for(int i=1;i<=n;i++){//循环输入有谁不懂吗?
		cin>>s[i];
		maxx=max(maxx,s[i]);//用max函数取最大值
		minn=min(minn,s[i]);//min函数取最小值
	}
	ans=maxx-minn;//最原始的没有加减k的大小差
	int c1=0,c2=0;//用来记最大值和最小值的数量
	for(int i=1;i<=n;i++){
		if(s[i]==minn) c1++;
		if(s[i]==maxx) c2++;
		if(s[i]!=minn&&s[i]<cmin) cmin=s[i];//次小
		if(s[i]!=maxx&&s[i]>cmax) cmax=s[i];//次大
	}
	if(c1>1&&c2>1){//如果得最大最小都出现不止一次,怎么加减都不会超过ans ,因为你想想,如果最大最小值都有两个及两个以上,怎么加减最大值最小值都是不变的,所以输出ans直接结束就可以了
		cout<<ans;
		return 0;
	}
	if(c1==1&&c2>1){//最小值一个最大值多个
		int t=k+minn;//最小值加上k,一下是+k的三种可能
		if(t>=cmin&&t<maxx){//大于等于次小,小于最大值
			ans=min(ans,maxx-cmin);//刷新ans
		}else if(t<cmin){//依旧是最小值
			minn=k+minn;//刷新min的值
			ans=min(ans,maxx-minn);//刷新ans
		}else if(t>maxx){//成为了新的最大值
			maxx=t;//最大值重新赋值
			ans=min(ans,maxx-cmin);//刷新ans
		}
	}else if(c2==1&&c1>1){//不多说了,和上面差不多
		int t=maxx-k;
		if(t<=cmax&&t>minn){
			ans=min(ans,cmax-minn);
		}else if(t>cmax){
			maxx=t;
			ans=min(ans,maxx-minn);
		}else if(t<=minn){
			minn=t;
			ans=min(ans,cmax-minn);
		}
	}else{//最大最小都只有一个
		if(k+minn<cmin){
			minn=k+minn;
			ans=min(ans,maxx-minn);
		}
		if(k+minn>=cmin&&k+minn<maxx){
			ans=min(ans,maxx-cmin);
		}
		if(k+minn>=maxx){
			maxx=k+minn;
			ans=min(ans,maxx-cmin);
		}
		if(maxx-k>cmax){
			maxx=maxx-k;
			ans=min(ans,maxx-minn);
		}
		if(maxx-k<=cmax&&maxx-k>minn){
			ans=min(ans,cmax-minn);
		}
		if(maxx-k<=minn){
			minn=maxx-k;
			ans=min(ans,cmax-minn);
		}
	}
	cout<<ans;
	return 0;
} 

我刚刚不是说被老师坑了一下吗?那么给大家看一看简易代码

#include<bits/stdc++.h>
using namespace std;
int n,k,a[10000005],b[10000005],sum1=0,sum2=0;
int main(){
	cin>>n>>k;
	k=abs(k);
	for(int i=1;i<=n;i++){
		cin>>a[i];
		b[i]=a[i];
	}
	sort(a+1,a+n+1);//依靠排序来寻找max和min值
	sort(b+1,b+n+1);//注意要用两个数组,一个看最大值-k一个看最小值+k
	a[1]+=k;
	b[n]-=k;
	sort(a+1,a+n+1);//再次进行排序寻找
	sort(b+1,b+n+1);
	sum1=a[n]-a[1];//第一个来判断min+k
	sum2=b[n]-b[1];//第二个来求max-k
	cout<<min(sum1,sum2);//输出两个的最小值
	return 0;
}

作者自述:这个题错的原因是底层思路不对,没有想到+/-k值的所有情况,只写了最大值减去k值,得0分

第三题《小可买菜》buy

问题描述

小可对达达真的是真爱!

小可为了体现对达达的爱,特意要为即将下班的达达做一顿丰富的晚饭!

做饭之前需要先购买足够的新鲜的食材,小可来到了超市。

小可列了一个购买清单,总共有 n 个食材需要购买,在超市中第 i 个食材的价格是 v​i​​。

今天超市正在进行促销活动,每满两个商品,都可以进行促销活动,使用两个商品中最高价格购买当前这两件商品。

为了节省金钱,小可还在线购买了 k 张超市折扣券,每两件商品可以使用一张折扣券,使用两个商品中最低价格购买当前这两件商品。

注意:商品不能重复参加活动。

请问小可购买清单中所有物品都购买后,最低花费多少元。

输入格式

第一行输入两个整数 n,k,含义如题所示。

第二行输入 n 个整数 v​i​​,数字以空格分隔,表示每个食材价格。

输出格式

输出一行包含一个整数,表示小可购买清单中所有物品都购买后,最低花费多少元。

输入样例1
4 1
1 2 3 4
输出样例1
4
输入样例2
10 2
1 3 2 4 7 8 9 6 3 8
输出样例2
20

这个题目用的是老朋友双指针lr了。目前买n个物品的优惠渠道有两个是不是?最好的一种就是代金券,买两个物品只需要付最便宜的一个物品的价钱,比如一个东西一毛钱,一个东西9999亿,那么用一毛钱就能白嫖9999亿的东西,岂不乐哉?第二种渠道就是正常活动,两个物品用最贵的物品的价格作为两个物品的总价,比如说一个东西9999亿,一个东西9998亿9999万9999元,那么用9999亿就能获得2倍价值的东西(这是一个例子,两倍不是固定,我的意思是用贵的与贵的的组合换取更多的利益)。众所周知利用双指针的是需要数组是有序序列,排序完之后先用代金券用便宜的钱白嫖贵的,代金券用完之后利用活动优惠,从末尾开始用最贵的嫖次贵的从而利益最大化,最后输出总钱数就可以了。

AC代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
long long  n,k,a[1000005];
int main(){
	//freopen("buy.in","r",stdin);
	//freopen("buy.out","w",stdout);
	cin>>n>>k;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	sort(a+1,a+n+1);//双指针利用前提需要排序
	long long  ll=1,rr=n,zongjia=0;//头和尾巴的定义
	for(int i=1;i<=k;i++){//循环k次用完代金券,这里写while也可以
		zongjia+=a[ll];//总价要加上头的,毕竟代金券是依靠便宜的嫖贵的
		//cout<<a[ll]<<endl;这个是遗弃代码懒得删了
		ll++;rr--;//头和尾巴都要往中间位置进一位
	}
	while(ll<=rr){//用活动卡bug嫖东西,<=的原因是奇数情况只剩一个,没发触发白嫖渠道
		zongjia+=a[rr];//活动嫖东西需要按贵的来,所以从尾巴出发
		rr-=2;//注意一次退两位
	}
	cout<<zongjia;//输出总价即可
	//fclose(stdin);
	//fclose(stdout);
	return 0;
} 
//10 2
//1 2 3 3 4 6 7 8 8 9
//1+2+3+6+8=20

作者自述:这个题错的有点离谱,没有写freopen("buy.in","r",stdin);freopen("buy.out","w",stdout);这俩玩意,并且第二个判断第二渠道循环不对,得10分

第四题《美味佳肴》

问题描述

吃面包要配果酱

吃薯条要配番茄酱

。。。

达达发现,小可准备的这些美食中,很多食物搭配起来吃最美味了!

小可为了让达达吃起来最顺利,已经给食物提前进行了标记,标记分为两种:大写字母 和 ?,相同大写字母表示两个食物搭配起来吃最美味,?则表示搭配任何一个食物吃都非常美味,但是达达有习惯,一旦使用当前这种食物搭配另一个食物,达达就不会再去搭配其他食物吃,也就是说每个?确定与某个食物搭配后,则不能再与其他食物搭配食用。

现在请问小可制作的饭菜中最多有多少种不同的搭配。

注意:

不同的搭配表示,字符相等,但是位置不同。

形式化的讲,给定一个由大写字母?构成的字符串 s ,在字符串中存在 l,r 满足 l<r 且 s[l]==s[r],则表示一种美味搭配。找出最多的不同的搭配,当 l 不同或 r 不同,就表示一种不同搭配。

输入格式

多组测试,第一行一个整数 T,表示测试组数。

然后对于每组测试数据,输入一个字符串s,含义如题所示。

输出格式

对于每组测试数据,输出一个整数,表示不同的搭配数量。

输入样例
4
?A?
ABCDBDABCDBA
ABCD?ACNBADADA
ERTETHD?ERY?ERHDFS?
输出样例
3
13
20
27

这个题就是搭配就行。相同的大写字母配相同的大写字母,“?”就相当于万能大写字母。那么这里面的变数有一个那就是“?”。我们要想一想怎么样才能利益最大化,题目既然是让我们求不同搭配,多的字母不同搭配自然会多,那么用“?”让多的字母更多,搭配更多,岂不乐哉?其实这题目描述和样例挺唬人,但是写出也不是很麻烦。

AC代码:

#include<iostream>
#include<cstring>
using namespace std;
int t;
long long a[95];//上面答题讲了一下要找出来次数最多的字母变得更多,那么就利用ACSII码帮助咱们
string s;
int main(){
	cin>>t;
	while(t--){
		memset(a,0,sizeof a);//memset全部赋初值为0,每次循环都是如此
		cin>>s;
		int maxx=0;
		long long ans=0;
		int len=s.size();//求长度,注意输入从0下标开始
		int temp;//最多的下标
		for(int i=0;i<len;i++){//找最多的字母
			a[s[i]]++;//出现即有
			if(s[i]!='?'){//如果这一位不是?,就可以参加“最多大写字母评选”
				if(a[s[i]]>maxx){//比最大值大的话
					maxx=a[s[i]];//赋值
					temp=s[i];//赋值
				}
			}
		}
		if(a['?']==0){//如果里面没有零的话
			for(int j=65;j<=90;j++){//正常来看
				ans+=a[j]*(a[j]-1)/2;//利用等差数列求和公式,(首项+末项)*项数/2
			}
		}else{//如果存在零
			a[temp]+=a['?'];//最大的字母数量变得更多
			for(int j=65;j<=90;j++){
				ans+=a[j]*(a[j]-1)/2;//同上不说了
			}
		}
		cout<<ans<<"\n";//最后输出即可
	}
	return 0;
}

作者自述:这道题也是思路不对,我的想法是从第一个字符开始,双层for循环遍历每一种可能,得0分

最后的最后,来水一下    

扯呢怎么可能?

总结这次的过失,下一次要好好考试考个好成绩(******要不是老师让我总结我写个dan,*太羞耻了)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值