【蓝桥杯】每日四道编程题(两道真题+两道模拟)| 第三天

专栏: 蓝桥杯——每日四道编程题(两道真题+两道模拟)
“蓝桥杯就要开始了,这些题刷到就是赚到”
₍ᐢ..ᐢ₎
另一个专栏: 蓝桥杯——每日四道填空题(两道真题+两道模拟题)

目录

专栏: 蓝桥杯——每日四道编程题(两道真题+两道模拟)

另一个专栏: 蓝桥杯——每日四道填空题(两道真题+两道模拟题)

第一道真题(2022年省赛): 最少刷题数

第二道真题(2022省赛):刷题统计

第三道模拟题(acwing):数的范围

第四道模拟题(2021年第三期模拟赛):时间显示


第一道真题(2022年省赛):最少刷题数

问题描述
小蓝老师教的编程课有 N 名学生, 编号依次是 1…N 。第 i 号学生这学期刷题的数量是 Ai​ 。

对于每一名学生, 请你计算他至少还要再刷多少道题, 才能使得全班刷题比他多的学生数不超过刷题比他少的学生数。

输入格式
第一行包含一个正整数 N 。

第二行包含 N 个整数:A1​,A2​,A3​,…,AN​.                         

输出格式
输出 N 个整数, 依次表示第 1…N 号学生分别至少还要再刷多少道题。

样例输入

5
12 10 15 20 6

样例输出

0 3 0 0 7

评测用例规模与约定
对于 30% 的数据,1≤N≤1000,0≤Ai​≤1000.

对于 100% 的数据, 1≤N≤100000,0≤Ai​≤100000.

这题就是考察我们处理问题的思维+二分就行了。(直接用lower_bound 和 upper_bound函数是真的爽,不过自己写也行,哈哈~)

lower_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于或等于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。


upper_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。

这题首先要先将数据排序,然后二分查找到它的中间数据(节约时间),中间数据右边的就不用考虑了,左边的需要把刷题数增加到比中间数据多一个。 但是目前我们还没有考虑到部分刷题数相同的数据怎么处理的问题,很显然如果是数据  12 15 15 15 20
此时我们的中间数据是15(下标3),那么此时我们左边右边的都需要考虑了.
此时就要保持这个区间[l , r](l是第一个15的下标,r是最后一个15的下标)不变。就只需要讨论它的左边,还有区间里的元素就可以了。建议看代码来理解 ~

#include 
using namespace std;
const int N = 1e5 + 100;
int n, a[N], b[N];
int main() {
    cin >> n;
    for (int i = 1; i <= n; ++i) cin >> a[i], b[i] = a[i];
    sort(b + 1, b + n + 1);
    int mid = 1 + n + 1 >> 1;
    int l = lower_bound(b + 1, b + n + 1, b[mid]) - b; //查找左区间l
    int r = upper_bound(b + 1, b + n + 1, b[mid]) - b - 1; //查找右区间r
    bool f = l - 1 > n - r ? true : false;  //如果区间左边的数据个数已经大于区间右边的数据个数,
                                           //那么只需要把刷题数增加到和中间数据相等就行了
                                           //为啥不能条件等于,因为你把数据增加过去了,左边就少一个了,条件不满足了
    for (int i = 1; i <= n; ++i) {
        if (a[i] == b[mid]) {   //讨论在区间里的元素
            if (l - 1 >= n - r) cout << 0 << " " ;  
            else cout << 1 << " " ;  
        }
        //讨论区间左边的值,右边不用考虑。
        else if (f) cout << max(0, b[mid] - a[i]) << " " ; //这里的max函数主要给区间右边给0就行了
        else cout << max(0, b[mid] - a[i] + 1) << " " ; 
    }
    return 0;
}

 第二道真题(2022省赛):刷题统计

问题描述
小明决定从下周一开始努力刷题准备蓝桥杯竞赛。他计划周一至周五每天 做 a 道题目, 周六和周日每天做 b 题目。请你帮小明计算, 按照计划他将在 第几天实现做题数大于等于 n 题?

输入格式
输入一行包含三个整数 a, b 和 n .

输出格式
输出一个整数代表天数。

样例输入

10 20 99

样例输出

8

【蓝桥杯】每日四道编程题(两道真题+两道模拟)| 第三天_第1张图片

这题比上面那到题简单多了,但是数据范围很大,记得用long long

由于n的数据范围很大,所以得先计算一下需要几周,在计算还需要几天。

#include 
using namespace std;
typedef long long LL;
LL a,b,n;
int main() {
	cin>>a>>b>>n;
	LL sum=a*5+b*2;//一周的做题数
	LL t=n/sum;//需要t周(往下取整)
	LL k=t*sum;//t周做了k个题目
	if(k>=n) cout<=n ) cout<= n ) cout<= n) cout<= n) cout<= n) cout<= n) cout<= n) cout<

第三道模拟题(acwing):数的范围

【蓝桥杯】每日四道编程题(两道真题+两道模拟)| 第三天_第2张图片

为了复习二分,我们手动写lower_bound 和 upper_bound函数。

#include 
using namespace std;
const int N=1e5;
int n,q,a[N],k;
int main()
{
	scanf("%d%d",&n,&q);
	for(int i=0;i>1;
	        if(a[mid]>=k) y=mid;
	        else{
	            x=mid+1;
	        }
	    }
	    if(a[x] != k){
	        printf("-1 -1\n");
	    }else {
	        printf("%d ",x);
	    int x1=0 , y1=n-1;
	    while(x1>1;  //这里避免死循环,要+1
	        if(a[mid]<=k)  x1=mid;
	        else{
	            y1=mid-1; }
	      }
	    printf("%d\n",y1);
	   }
	}
	return 0;
 } 

第四道模拟题(2021年第三期模拟赛):时间显示

【问题描述】

​ 小蓝将自己的车停在路边,在同一天将车开走。给定停车时间和开走时间,请问小蓝停了多长时间?

【输入格式】

​ 输入两行,第一行包含停车时间,第二行包含开走时间。

​ 每个时间的格式为 HH:MM:SS,其中 HH 表示时,值为 0 到 23 的整数,如果小于 10 用 0 补齐两位;MM 和 SS 分别表示分和秒,值为 0 到 59 的整数,小于 10 时用 0 补齐两位。

【输出格式】

​ 输出总共停车的时间,格式为 HH:MM:SS。

【样例输入】

08:58:10
17:20:31

【样例输出】

08:22:21

这题不是我摆烂,而是想复习一下时间的相关计算,即时、分、秒的转换。

这里输出的前导零,用c 的输出方式就可以了(占位符)。

#include 
using namespace std;

int main() {
	int begin, end, ans;
	int hh, ff, ss;

	scanf("%d:%d:%d", &hh, &ff, &ss);
	begin = hh * 3600 + ff * 60 + ss;

	scanf("%d:%d:%d", &hh, &ff, &ss);
	end = hh * 3600 + ff * 60 + ss;

	ans = end - begin;

	printf("%02d:%02d:%02d\n", ans / 3600, (ans / 60) % 60, ans % 60);

	return 0;
}

你可能感兴趣的:(蓝桥杯——编程题刷题营,蓝桥杯,c++)