(Training 16)Codeforces Round #687

A. Prison Break

题意:给出地图大小n*m 和点 (x,y)问地图上距离该点最远的点是多少
思路:4个角落必然最远 取最大即可

#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
int main(){
	int T;
	cin>>T;
	while(T--){
		int n,m,x,y;
		cin>>n>>m>>x>>y;
		cout<<max({x-1+y-1,m-x+n-y,n-x+y-1,x-1+m-y})<<endl;
	} 
}

B. Repainting Street

题意:长度为n的图 大小为K的刷子 问最少多少次能将图刷为一个颜色
思路:首先一共10种 地图长度是1e5
那么我们直接向后枚举 统计上次颜色出现的位置 和 上次 刷该颜色时颜色最后保留的位置 求出需要刷多少次即可 累加求出结果
最后再以n为结尾点统计一次答案即可

#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
const int N=1e3+10;
int cnt[N],pre[N],pro[N];
int a[100010];
int main(){
	int T;
	cin>>T;
	while(T--){
		int n,k;
		scanf("%d%d",&n,&k);
		memset(cnt,0,sizeof cnt);
		memset(pre,0,sizeof pre);
		memset(pro,0,sizeof pro);
		
		for(int i=1;i<=n;i++){
			int x;
			scanf("%d",&x);
			a[i]=x;
			if(pre[x]<i-1&&pro[x]<i-1){//上次涂色位置大于K 
				int t=(i-1-max(pre[x],pro[x])+k-1)/k;//求出需要刷多少次
				cnt[x]+=t;
				pro[x]=max(pro[x],pre[x])+k*t;
			}
			pre[x]=i;
		}
		int ans=0x3f3f3f3f;
		for(int i=1;i<=100;i++){
			if(pre[i]<n&&pro[i]<n)
			cnt[i]+=(n-max(pre[i],pro[i])+k-1)/k;
			ans=min(ans,cnt[i]);
		}
		
		cout<<ans<<endl;
	} 
}

C. Bouncing Ball

题意:删除第一个点的时间为y 将一个点变为1的时间为x
求出使得平台的第p个点和分别 第p+k p+2k…个点都能满足这几个位置为1
思路:因为只能删除前面 所以我们考虑从后往前统计
h[i]=h[i+k]+1sum[i]=sum[i+k]+(str[i]=='1')
即位置i为p的话 需要多少个1和位置i有多少个1
这时候我们就知道了 再从前往后推一次 取min

#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
const int N=2e5+10;
char str[N];
int sum[N],h[N];
int main(){
	int T;
	cin>>T;
	while(T--){
		int n,k,p;
		memset(sum,0,sizeof sum);
		memset(h,0,sizeof h);
		scanf("%d%d%d",&n,&p,&k);
		scanf("%s",str+1);
		int x,y;
		scanf("%d%d",&x,&y);
		//cout<<x<<" "<<y<<endl;
		int ans=1e9+10;
		for(int i=n;i>=1;i--){
			h[i]+=h[i+k]+1;
			sum[i]+=sum[i+k]+(str[i]=='1');
		}
		for(int i=1;i<=n;i++){
			if(i>=p){
				ans=min(ans,y*(i-p)+(h[i]-sum[i])*x);
				//cout<<y*(i-p)<<" "<<i-p<<" "<<(h[i]-sum[i])<<" "<<y<<endl;
			}
		}
		cout<<ans<<endl;
	} 
}

D. XOR-gun

题意:给出一个升序(ai<=aj,i<j)的数组
可以选择2个数将他进行异或运算后加入数组中
可以不断进行该操作 最少多少次操作能使得数组不满足升序
在这里插入图片描述

思路:这个并不是个数据结构(字典树)
而需要观察 由于是异或操作 我们考虑二进制
因为每个数均小于1e9
转换为2进制后 最高的数有30位
如果相邻2个数进行异或操作后 他小于左边的数 那么他们这2个数必定高位相同这样异或操作后高位被消去 那么当如果相邻有3个数的最高位相同 那么必然操作数为1 而当超过60个数以后 就必定有相邻有3个数的最高位相同 而这时候 我们只需要考虑小于60的情况 那么我们只要进行枚举即可 不管是3次方 4次方也好。。。都能过

#include<iostream>
#include<cstring>
#include<vector>
#include<map>
#include<algorithm>
using namespace std;
const int N=1e5+10;
int a[N];
int main(){
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
		a[i]^=a[i-1];
	}
	if(n>=60){
		return puts("1"),0;
	}
	int ans=n;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=i;j++)
			for(int k=i+1;k<=n;k++){
				if((a[i]^a[j-1])>(a[i]^a[k]))//(i+1到K k-i-2次)(i-j+1次) 
				ans=min(ans,k-j-1);
			}
	}
	if(ans!=n)
	cout<<ans;
	else puts("-1");
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值