Educational Codeforces Round 169 (Rated for Div. 2) (A~D)

Educational Codeforces Round 169 (Rated for Div. 2)

写在前面

手速场,半小时A出3道题,后面直接坐牢1个多小时······,D题看了半天,有思路却不会写,赛后看了一下大佬们的代码确实非常好,我自己是写不出来的,E题博弈论没怎么学,就不补了QVQ

A. Closest Point

思路

签到题 ,有2种情况:

  • n > 2 n>2 n>2 时,无论放哪都不满足题意
  • n < = 2 n<=2 n<=2 时,n为1 或者 这两个数不相邻,那就满足题意

题目说明是一条直线,那么数没有重复且都是升序的

code

int a[N];
void solve(){
	int n;cin >> n;
	for(int i=1;i<=n;++i){
		cin >> a[i];
	}
	if(n>2) cout << "NO" << endl;
	else{
		if(n==1 || a[2]-a[1]!=1) cout << "YES" << endl;
		else cout << "NO" << endl;
	}
	return ;
}

B. Game with Doors

思路

这题需要考虑4种情况:

  • Alice和Bob没有相交的区域,那么只需要关闭一扇门即可
  • Alice和Bob完全重合,那么这些门需要全部关闭,即 r − l r-l rl
  • Alice和Bob的左边界或者右边界有重合,(那么我们拿右边界重合为例,我们找出他们两左边界的最大值
  • a n s = r − m a x ( l , L ) + 1 ans=r-max(l,L)+1 ans=rmax(l,L)+1首先r到max(l,L)的门必须关闭,那么假设l<L,L到L-1和L Alice和Bob会有交界,这个门也需要关闭
  • Alice和Bob相交无重合, a n s = m i n ( r , R ) − m a x ( l , L ) + 2 ans=min(r,R)-max(l,L)+2 ans=min(r,R)max(l,L)+2 ,重合的部分需要关闭且重合的边界也需要关闭

code

void solve(){
	int a,b;
	cin >> a >> b;
	int l,r;
	cin >> l >> r;
	if(b<l || r<a){
		cout << 1 << endl;
		return ;
	}
	if(a==l && b==r){
		cout << b-a << endl;
		return ;
	}
	int k=max(a,l);
	int s=min(b,r);
	if(a==l || b==r){
		cout << s-k+1 << endl;
		return ;
	}
	else{
		cout << s-k+2 << endl;
		return ;
	}
	return ;
}

C. Splitting Items

思路

考点:贪心+模拟

由于Alice先手,那么每次Alice所拿的数>=Bob所拿的数
那么对于Bob来说,最优解自然是0
我们先将数进行升序排序,对于Bob来说,他需要操作的数都是偶数次的下标
对于这些数来说,让他们尽可能和上一个数相同即可

code

const int N=1e6+5;
int a[N];
bool cmp(int x,int y){
	return x>y;
}
void solve(){
	int n,k;
	cin >> n >> k;
	for(int i=1;i<=n;++i) cin >> a[i];
	sort(a+1,a+1+n,cmp);
	int sum1=0,sum2=0;
	for(int i=2;i<=n;i+=2){
		int s=a[i-1]-a[i];
		if(k>=s){
			a[i]+=s;
			k-=s;
		}
		else{
			a[i]+=k;
			break;
		}
	}
	for(int i=1;i<=n;++i){
		if(i & 1) sum1+=a[i];
		else sum2+=a[i];
	}
	cout << sum1-sum2 << endl;
	return ;
}

D. Colored Portals

思路

考点:二分+贪心

首先,x移动到y有3种可能:

  • x可以直接到y,他的成本就为y-x
  • x到y之间有一个中转点,x可以先到中转点在到y,成本也为y-x
  • 考虑贪心策略,假设中转点在x左侧或者y右侧,我们尽可能让这个中转点靠近x或者靠近y,这样他的成本最低

这时我们可以用二分去优化这个查找的范围,思路不难,难点在于代码的实现

接下来直接看代码吧~~

code

const int N=1e6+5;
string s[N];
void solve(){
	map<string,vector<int>> m;
	int n,q;
	cin >> n >> q; 
	for(int i=1;i<=n;++i){
		cin >> s[i];
		m[s[i]].push_back(i);//将当前字符串的下标存进去
	}
	while(q--){
		int x,y;
		cin >> x >> y;
		int ans=inf;
		if(x>y) swap(x,y);//让x<y
		for(auto i : s[x])
		   for(auto j : s[y]){
		   	   if(i==j){//x和y能直接到达
		   		  ans=y-x;
		   		  break;
			     }
			   string t="";
			   t+=i,t+=j;
			   if(t[0]>t[1]) swap(t[0],t[1]);//题目是按字典序的排序,小的在前面
			   auto mid=lower_bound(m[t].begin(),m[t].end(),x);
			   if(mid!=m[t].end() && (*mid)<=y) ans=y-x;//先判断中转点是否在中间
			   auto l=mid;
			   auto r=upper_bound(m[t].begin(),m[t].end(),y);//找y右边的中转点
			   if(l!=m[t].begin()){//判断m[t]是否为空,这时l指向的是m[t].end()或者第一个大于等于x的数
			   	l--;
			   	ans=min(ans,(x-*l)*2+(y-x));
			   } 
			   if(r!=m[t].end()) ans=min(ans,(*r-y)*2+(y-x));
		   }
		cout << (ans==inf?-1 : ans) << endl;
	}
	return ;
}
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值