学号: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
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,⋯,S1,S2,⋯,Sn。
定义数组 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≤Si,k≤1000
对于 100%100% 的数据:2≤106,0≤1082≤n≤106,0≤∣Si∣,∣k∣≤108。
老师讲这一道题的时候我们被阴险的老师狠狠地坑了一波……
思考一下下,这道题有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 个食材的价格是 vi。
今天超市正在进行促销活动,每满两个商品,都可以进行促销活动,使用两个商品中最高价格购买当前这两件商品。
为了节省金钱,小可还在线购买了 k 张超市折扣券,每两件商品可以使用一张折扣券,使用两个商品中最低价格购买当前这两件商品。
注意:商品不能重复参加活动。
请问小可购买清单中所有物品都购买后,最低花费多少元。
输入格式
第一行输入两个整数 n,k,含义如题所示。
第二行输入 n 个整数 vi,数字以空格分隔,表示每个食材价格。
输出格式
输出一行包含一个整数,表示小可购买清单中所有物品都购买后,最低花费多少元。
输入样例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,*太羞耻了)