2024.4.2abc晚训题解

题目地址https://vjudge.net/contest/620054#problem/A
清明节假日不组织晚训,两个任务
1 订正以前晚训的错题
2 尽量做做清明节算法专题VJ

A题
主要是判断往回喝水还是向前走一站再喝水,考虑5的余数即可

#include<bits/stdc++.h>
using namespace std;
int main(){
	int n;
	cin>>n;
	if(n%5==0)cout<<n;
	else if(n%5<=2)cout<<n/5*5;
	else cout<<n/5*5+5;
	return 0;
}

B题
简单模拟题

#include<bits/stdc++.h>
using namespace std;
int A[50];
int main(){
	A[1]=0;
	A[2]=A[1]+3;
	A[3]=A[2]+1;
	A[4]=A[3]+4;
	A[5]=A[4]+1;
	A[6]=A[5]+5;
	A[7]=A[6]+9;
    char p,q;
    cin>>p>>q;
    cout<<abs(A[p-'A'+1]-A[q-'A'+1]);
	return 0;
}

C题
至少是一个 2 ∗ 2 2*2 22的饼干矩形,那么我们直接判断所有的 . . .即可
判断有 . . .的地方,作为 2 ∗ 2 2*2 22饼干矩形的哪一个角。注意边界的判断
一定要先判断越界,再判断是什么元素,不要放在一起判断

#include<bits/stdc++.h>
using namespace std;
char s[505][505];
int n,m;
bool check(int x,int y){
	//左上 
	if(y+1<=m&&x+1<=n){
		//?*
		//**
		if(s[x][y+1]==s[x+1][y]&&s[x+1][y]==s[x+1][y+1]&&s[x][y+1]=='#')return true;
	}
	//右上
	if(y-1>=1&&x+1<=n){
		//*?
		//**
		if(s[x][y-1]==s[x+1][y]&&s[x+1][y]==s[x+1][y-1]&&s[x][y-1]=='#')return true;
	} 
	//左下
	if(y+1<=m&&x-1>=1){
		//**
		//?*
		if(s[x][y+1]==s[x-1][y]&&s[x-1][y]==s[x-1][y+1]&&s[x][y+1]=='#')return true;
	} 
	//右下
	if(y-1>=1&&x-1>=1){
		//**
		//*?
		if(s[x][y-1]==s[x-1][y]&&s[x-1][y]==s[x-1][y-1]&&s[x][y-1]=='#')return true;
	} 
	return false;
}
int main(){

	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>s[i]+1;
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if(s[i][j]=='.'){
				bool ok=check(i,j);
				if(ok){
					cout<<i<<" "<<j;
					return 0;
				}
			}
		}
	}
	return 0;
}

D题
经典的区间询问问题
不难发现本题范围很大,但是N一般般大
A A A数组相当于是睡眠的记录数组,偶数位置是开始睡觉的时间,奇数位置是醒来时间,我们可以考虑记录一个睡眠累计时长的前缀和 s u m [ i ] sum[i] sum[i]
表示 1 − − i 1--i 1i 睡眠的总时间
观察 A [ 1 ] , A [ 2 ] , A [ 3 ] . . . . . A [ x ] , L , A [ x + 1 ] . . . A [ y ] , R . . A [ n ] A[1],A[2],A[3].....A[x],L,A[x+1]...A[y],R..A[n] A[1],A[2],A[3].....A[x],L,A[x+1]...A[y],R..A[n]
我们查询的时间线 L , R L,R L,R必定会在 A A A数组中呈现如此状态
所以我们考虑二分查找,找到 L , R L,R L,R A A A数组中(最接近的不大于的元素位置),有了位置就可以考虑利用前缀和处理。例如我们可以直接计算出 s u m [ x ] , s u m [ y ] sum[x],sum[y] sum[x],sum[y] ,再根据二分查找得到的下标精确计算出 A [ x ] − − L A[x]--L A[x]L的时间里面睡眠了多久( A [ x ] A[x] A[x]要么是醒来的时间,要么是睡觉的时间点, A [ y ] A[y] A[y]同理),然后利用减法即可计算出 L − − R L--R LR分钟睡觉了多久

#include<bits/stdc++.h>
using namespace std;
long long int sum[200005];
long long int A[200005];
bool check(int pos,int vel){
	if(A[pos]<=vel)return true;
	else return false;
}
int main(){
	int n;
	cin>>n;
	for(int i=1;i<=n;i++) {
		cin>>A[i];
		if(i%2==1){
		sum[i]=sum[i-1]+(A[i]-A[i-1]);//睡眠前缀和 
		}
		else sum[i]=sum[i-1]; 
		
	}
	int q;
	cin>>q;
	while(q--){
	int l,r;
	cin>>l>>r;
	int L=1,R=n;
	int pos_L,pos_R;
	while(L<R){
		int mid=(R+L+1)/2;
		if(check(mid,l)){
			L=mid;
		}	
		else{
			R=mid-1;
		}
	}
	pos_L=L;
	L=1,R=n;
	while(L<R){
		int mid=(R+L+1)/2;
		if(check(mid,r)){
			L=mid;
		}	
		else{
			R=mid-1;
		}
	}
	pos_R=L;
	long long int time_L;
	long long int time_R;
	if(pos_L%2==0){
	time_L=sum[pos_L]+l-A[pos_L];	
	}
	else{
	time_L=sum[pos_L];	
	}
	if(pos_R%2==0){
	time_R=sum[pos_R]+r-A[pos_R];	
	}
	else{
	time_R=sum[pos_R];	
	}
	cout<<time_R-time_L<<'\n';
	}	
	return 0;
}

E题
简单语法题,输出有点小技巧会方便点,像一般遇到环状的数据,我们考虑把数据从0位置存入

#include<bits/stdc++.h>
using namespace std;
struct pe{
	int year;
	char name[30];
}A[110];
int main(){
	int n;
	scanf("%d",&n);
	int mi=1e9;
	int pos;
	for(int i=0;i<n;i++){
		scanf("%s%d",A[i].name+1,&A[i].year);
		if(A[i].year<mi){
			mi=A[i].year;
			pos=i;
		}
	}
	printf("%s\n",A[pos].name+1);
	int now=(pos+1)%n;
	while(now!=pos){
		printf("%s\n",A[now].name+1);
		now=(now+1)%n;
	}
	return 0;
}

F题
本题方法很多,我用的是“递减”思维
n n n只要 ≥ ≥ 10 3 就要截断,统计截断了多少次,就输出的时候补0

#include<bits/stdc++.h>
using namespace std;
int main(){
	int n;
	cin>>n;
	int base=1000;
	int ok=0;
	for(int i=1;i<=6;i++){
		if(n>=base)n=n/10,ok++;
	}
	cout<<n;
	for(int i=1;i<=ok;i++)cout<<0;
	return 0;
}

G题
临时加的一道题目,担心本套晚训题目组的太简单了QAQ
一个一个枚举肯定是不行的,必定超时,
我们考虑每个 A [ i ] A[i] A[i]如何来组成贡献
因为差至多为D,而且还要加起来的和尽可能大,实际上最优的答案对于 A [ i ] A[i] A[i]来说就是 A [ i ] + D A[i]+D A[i]+D 我们把它当成检查的判断,对排序(从小到大)后的 B B B数组进行二分查找,寻找 B [ m i d ] + A [ i ] ≤ A [ i ] + D B[mid]+A[i]≤A[i]+D B[mid]+A[i]A[i]+D 如果成立,我们尽可能地逼近 A [ i ] + D A[i]+D A[i]+D 也就是我们需要把答案范围朝着大的方向变,也就是 L = m i d L=mid L=mid
当然如果找不到解最终要输出-1


#include<bits/stdc++.h>
using namespace std;
long long int A[200005];
long long int B[200005];
int main()
{
    int n,m;
    long long int d;
    cin>>n>>m>>d;
    for(int i=1;i<=n;i++){
    	cin>>A[i];
	}
	for(int i=1;i<=m;i++){
    	cin>>B[i];
	}
	sort(B+1,B+1+m);
	long long int ans=0;
	for(int i=1;i<=n;i++){
		//A[i]   A[i]+D
		int L=1,R=m;
		while(L<R){
			int mid=(L+R+1)/2;
			if(B[mid]<=A[i]+d){
				L=mid;
			}
			else{
				R=mid-1;
			}
		}
		long long int now=A[i]-B[L];
		if(now<0)now=-now;
		if(now<=d&&A[i]+B[L]>ans){
			ans=A[i]+B[L];
		}
	}
	if(ans==0){
		cout<<-1;
	}
	else cout<<ans;
    return 0;
}

每日积累的知识,每天放弃的娱乐时间,势必化成我前进的力量

  • 19
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值