莆田市第四批C++选拔 第一轮比赛已经结束了,那么如果需要订正的话,可以点赞收藏。如果没有参加的话也可以知识总结,希望对你有帮助。
以下代码和解析都是本人写的,都是100分的,只是非官方答案。
一、光阴似箭
题目背景
光阴似箭,日月如梭。时钟滴滴答答,时间一分一秒的过去,我们总是在不知不觉中度过了一天又一天。
题目描述
因为地球自转的原因,我们人类实行二十四小时制,将一天分为了 24 小时,每小时 60 分钟。现已知当前时间是 a 小时 b 分钟,请问经过 s 分钟后的时间是多少?
请注意,每天的时间是循环的,即 23 时 59 分后的 1 分钟后是 0 时 0 分。
输入格式
一行三个整数 a,b,s,分别表示当前时间的小时、分钟和经过的时间。
输出格式
一行两个整数,分别表示 s 分钟后的时间的小时和分钟。
样例数据
输入样例 #1
3 5 10
输出样例 #1
3 15
输入样例 #2
23 59 1
输出样例 #2
0 0
数据范围
对于 50% 的数据,。
对于 100% 的数据,,
,
。
解析
首先,我们看到这道题,必须先想一想它让我们求的是时间,那么我们可以将 除以1440,因为一天刚好有1440分钟,加一天也是原来的时间。比如说:s为2880,a为13,b为30,那么过完2880分钟,也是原来的时间。就算加几天都是原来的时间,不仅这样可以优化代码,还让后面会更好写一点。
然后,就是求时间了。先把 加上已经取模好的
,然后
加上(
模
)(也就是把
加上多出来的多少小时),再把
除以
,也就是现在的分钟数。最后判断
是否大于
,大于
就减去
。
最后,就求出了 和
的值。
当然,有50%的数据时b+s小于59,只要b+s就可以了,不用作更多的运算。
代码
#include<bits/stdc++.h>
using namespace std;
int main(){
int a,b;
long long s;
cin>>a>>b>>s;
s%=1440;
b+=s;
a+=b/60;
b%=60;
if(a>=24){
a-=24;
}
cout<<a<<" "<<b;
return 0;
}
二、日月如梭
题目背景
光阴似箭,日月如梭。人生短暂,时间宝贵,我们要在有限的时间里去做更多有意义的事情。
题目描述
这不,在一年一度的班长选举中,小明、小红和小李都想要竞争班长。
经过一轮激烈的角逐,最终小明、小红和小李都得到了一定数量的选票,分别为 a、b 和 c 张。
你需要计算,对于每一个班长候选人,他需要再得到多少张选票才能成为班长呢?
当上班长的条件为,得到的选票数要超过其他两位候选人的选票数。
输入格式
一行三个整数 a,b,c,分别表示小明、小红和小李得到的选票数。
输出格式
一行三个整数,分别表示小明、小红和小李需要再得到的选票数。
样例数据
输入样例 #1
12 13 17
输出样例 #1
6 5 0
数据范围
对于 20% 的数据,a=b=c。
对于 50% 的数据,a≤b≤c。
对于 100% 的数据,0≤a,b,c≤105。
解析&代码
20pt
因为a=b=c,那么每个人只要再投一票就可以当选班长,直接输出1 1 1。所以我们可以这样:
#include<bits/stdc++.h>
using namespace std;
int main(){
long long a,b,c;
cin>>a>>b>>c;
if(a==b&&b==c){
cout<<"1 1 1";
}
return 0;
}
50pt
因为 a≤b≤c ,那么我们可以找出最大的那个数,然后再把其他两个数与这个最大的数相减的差加1,而最大那个数不用再投票就能竞选班长。(这么算是因为其他两个人再投到与最大那个数一样时,再投一票就可以竞选班长)。所以我们可以得出以下代码:
#include<bits/stdc++.h>
using namespace std;
int maxx(int x,int y,int z){
if(x>y) swap(x,y);
if(y>z) swap(y,z);
if(x>y) swap(x,y);
return z;
}
int main(){
long long a,b,c;
cin>>a>>b>>c;
if(a==b&&b==c){
cout<<"1 1 1";
return 0;
}
int num=maxx(a,b,c);
int numa=0,numb=0,numc=0;
if(num==a){
numb=num-b+1;
numc=num-c+1;
}else if(num==b){
numa=num-a+1;
numc=num-c+1;
}else{
numb=num-b+1;
numa=num-a+1;
}
cout<<numa<<" "<<numb<<" "<<numc;
return 0;
}
100pt
那么剩下我们就要考虑:当a=b=c时;当有两个数相等时;当每个数都不想同时。从这三个方面考虑。而且我们要在分支一下:在有两个数相等时,这两个相等的数是否是小于第三个数,还是大于第三个数?如果这些你都考虑到了,那么你真是个细心的程序员。
所以代码就如下:
#include<bits/stdc++.h>
using namespace std;
int maxx(int x,int y,int z){
if(x>y) swap(x,y);
if(y>z) swap(y,z);
if(x>y) swap(x,y);
return z;
}
int main(){
long long a,b,c;
cin>>a>>b>>c;
if(a==b&&b==c){
cout<<"1 1 1";
return 0;
}
int num=maxx(a,b,c);
int numa=0,numb=0,numc=0;
if(a==b||a==c||b==c){
if(a==b){
if(a<c){
numa=c-a+1;
numb=numa;
}else{
numa=numb=1;
numc=a-c+1;
}
}else if(b==c){
if(b<a){
numb=a-b+1;
numc=numb;
}else{
numc=numb=1;
numa=c-a+1;
}
}else{
if(c<b){
numc=b-c+1;
numa=numc;
}else{
numc=numa=1;
numb=a-b+1;
}
}
}else{
if(num==a){
numc=a-c+1;
numb=a-b+1;
}else if(num==b){
numa=b-a+1;
numc=b-c+1;
}else{
numa=c-a+1;
numb=c-b+1;
}
}
cout<<numa<<" "<<numb<<" "<<numc;
return 0;
}
三、倒水
题目描述
现给你 2 个水杯,容量分别为 a 和 b。最开始时,1 号水杯和 2 号水杯都是空的。
现你要按照如下规则操作倒水 k 次:
- 如果 1 号杯子水是满的,则将 1 号杯子中的水全部倒掉。
- 否则如果 2 号杯子是空的,则将 2 号杯子装满水。
- 否则,将 2 号杯子的水全部倒入 1 号杯子,直到 1 号杯子装满水或 2 号杯子水为空。
请问 k 次操作后,1 号杯子和 2 号杯子中的水量分别是多少?
输入格式
一行三个整数 a,b,k,分别表示 1 号杯⼦的容量,2 号杯子的容量和操作次数。
输出格式
一行两个整数,分别表示 1 号杯子和 2 号杯子中的水量。
样例数据
输入样例 #1
3 5 2
输出样例 #1
3 2
第一次操作,给 2 号杯子装满水,水量分别为 0,5; 第二次操作,将 2 号杯子的水全部倒入 1 号杯子,直到 1 号杯子装满水,水量分别为 3,2。
输入样例 #2
2 6 3
输出样例 #2
0 4
数据范围
对于 20% 的数据,k=1。
另有 30% 的数据,b 是 a 的倍数。
对于 100% 的数据,1≤a,b≤105,1≤k≤105。
解析&代码
20pt
因为k=1,说明只要进行一次操作。那么我们就直接知道b杯子为空杯子,只要b杯子装满水就可以了。那么直接输出0和b,所以代码如下:
#include<bits/stdc++.h>
using namespace std;
int main(){
long long a,b,k;
cin>>a>>b>>k;
cout<<0<<" "<<b;
return 0;
}
30pt
(见100分代码,因为这跟100分只差了一点,我就懒得写了)
100pt
我们可以建立两个变量numa和numb,分别表示a水杯的水量和b杯子的水量。然后进行k次操作。(一点一点来)
先是判断a杯子是否是满的,满的话则numa=0(把a中的水倒掉)。
然后再判断b杯子是否为空的,空的话则numb=b(把b杯子装满)。
最后也就是最关键的,题目说直到a水杯满了或b水杯空为止。那么,我们就得想:a-numa(也就是a水杯所空的位置)的值是否能被numb(b水杯里现在有的水)给倒满。如果能倒满,那么numa=a(杯子a被灌满),而b则减去a-numa(也就是把b水杯里的水倒进a水杯所空的位置所剩下的);但是如果倒不满,则a+=numb,b水杯里的水就为空了。
如果可以的话,在进行这些判断时可以直接判断a水杯是否满了或者b水杯是否空了,只要满足其中一个条件,就continue。
所以代码就如下了:
#include<bits/stdc++.h>
using namespace std;
int main(){
long long a,b,k;
cin>>a>>b>>k;
int numa=0,numb=0;
for(int i=1;i<=k;i++){
if(numa==a){
numa=0;
}else if(numb==0){
numb=b;
}else{
if(numa==a||numb==0){
continue;
}
if(a-numa>numb){
numa+=numb;
numb=0;
}else{
numb-=a-numa;
numa=a;
}
}
}
cout<<numa<<" "<<numb;
return 0;
}
四、硬币
题目描述
小明同学是一个硬币收集者,收集了很多不同面值的硬币。
现在他把这些硬币分成了两堆,已知两堆硬币分别有 n 和 m 枚硬币。
第一堆里有 n 枚面值为 b1,b2,…,bn 的硬币。第二堆里有 m 枚面值为 c1,c2,…,cm 的硬币。现在小明同学想要从两堆硬币中各选择一枚硬币,使得两枚硬币的面值之和 不超过 k。
请你帮助小明同学计算一下他有多少种选择方案。 不同的硬币组合,就算面值相同,也视为不同的方案。
输入格式
第一行三个整数 n,m,k,分别表示第一堆硬币的数量,第二堆硬币的数量,以及面值之和的上限。
第二行 n 个整数 b1,b2,…,bn,表示第一堆硬币的面值。
第三行 m 个整数 c1,c2,…,cm,表示第二堆硬币的面值。
输出格式
输出一个整数,表示小明同学有多少种选择方案。
样例数据
输入样例 #1
4 4 8
1 5 10 14
2 1 8 1
输出样例 #1
6
可选方案有: (1,2),(1,1),(1,1),(5,2),(5,1),(5,1),共 6 种。
输入样例 #2
2 3 4
4 8
1 2 3
输出样例 #2
0
数据范围
对于 30% 的数据,,
。
对于 60% 的数据,,
。
对于 100% 的数据,,
,
。
解析&代码
30pt
用普通的方法,那就是一个一个循环遍历过去,这个方法比较简单,我就不再多说了。
代码如下:
#include<bits/stdc++.h>
using namespace std;
long long n,m,k,Sum,b[10000000],c[10000000];
int main(){
cin>>n>>m>>k;
for(int i=1;i<=n;i++){
cin>>b[i];
}
for(int i=1;i<=m;i++){
cin>>c[i];
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(b[i]+c[j]<=k){
Sum++;
}
}
}
cout<<Sum;
return 0;
}
50pt
我们可以换个思路,把b数组和c数组进行排序。然后再一次次的遍历,只要相加小于k,num就加一,如果相加大于k,则跳出本次循环(因为已经排好序了,后面的数再怎么加都大于k),并让Sum加上本次循环的num,也就是符合的方案,然后再进行下一次循环。
所以代码如下:
#include<bits/stdc++.h>
using namespace std;
long long n,m,k,Sum,b[10000000],c[10000000];
int main(){
cin>>n>>m>>k;
for(int i=1;i<=n;i++){
cin>>b[i];
}
sort(b+1,b+1+n);
for(int i=1;i<=m;i++){
cin>>c[i];
}
sort(c+1,c+1+m);
for(int i=1;i<=n;i++){
int num=0;
for(int j=1;j<=m;j++){
if(b[i]+c[j]>k){
break;
}
num++;
}
Sum+=num;
}
cout<<Sum;
return 0;
}
100pt
如果还是像上面一样的话,则会TLE,那么我们可以用二分查找来解决问题。
第一步用Sort排序,将两堆硬币按从小到大顺序分别排一下,
第二步 for循环遍历其中一堆硬币a,再用定值k减去我所遍历的硬币值得到s,
第三步 在另一堆硬币b当中用二分法找到满足小于等于s的那个硬币最大值所在的位置l,找到之后,那么我们算一下对于当下遍历这一堆a当中的这个硬币值,另一堆b当中能有多少种组合,就是这个l位置往前的,其实就是l种组合。(这个思路是我老师提供的)
所以代码如下:
#include<bits/stdc++.h>
using namespace std;
long long n,m,k,t,mid,l,r,Sum,b[10000000],c[10000000];
int main(){
cin>>n>>m>>k;
for(int i=1;i<=n;i++){
cin>>b[i];
}
sort(b+1,b+1+n);
for(int i=1;i<=m;i++){
cin>>c[i];
}
sort(c+1,c+1+m);
c[m+1]=c[m];
for(int i=1;i<=n;i++){
t=k-b[i];
l=1;
r=m+1;
if(t>0){
while(l<r){
mid=(l+r)/2;
if(t>=c[mid]){
l=mid+1;
}else{
r=mid;
}
}
}
Sum+=l-1;
}
cout<<Sum;
return 0;
}
小结
这次比赛比较简单,分数线为100分,所以这几道题比较简单,如果有不懂的或哪个细节没写清楚,欢迎在评论区里留言。感谢支持与鼓励!!!