2021-02-25 Codeforces Round #703 (Div. 2)

A. Shifting Stacks

呜呜,比赛时A题就做了一小时
注意积木只能往后移动,可以这样理解,只要此时的积木总数大于能满足递增序列的积木总数的最小数即可。
最小积木数 0 1 2 3 4 5 6 7 8…
如果积木多出来了,只要将多余的积木放在最后就行。
因为积木只能向后移动,所以要遍历判断n个区间。

#include<bits/stdc++.h>
using namespace std;
int t, n;
typedef long long ll;
ll h[102];
int main(){
	cin >> t;
	while(t--){
		cin >> n;
		ll sum=0, sum1=0;
		bool f=1;
		for(int i=0; i<n; ++i){
			cin >> h[i];
			sum += i;
			if(f){
				if(sum1+h[i] >= sum){
				sum1 += h[i];
			    }
			else f=0;
			}
		}
		if(f) cout << "yes" << endl;
		else cout << "no" << endl;
	}
}

B. Eastern Exhibition

先看下货舱选址的结论

求|x1−x2|+|y1−y2|的最小值,只要|x1−x2|和|y1−y2|都是最小即可
n为奇数时,一个点。
n为偶数时,算下乘积。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int t, n;
ll x[1003], y[1003];
int main(){
	cin >> t;
	while(t--){
		cin >> n;
		for(int i=1; i<=n; ++i){
			cin >> x[i];
			cin >> y[i];
		}
		sort(x+1, x+n+1);
		sort(y+1, y+n+1);
		if(n%2 == 1) cout << '1' << endl;
		else {
			ll sum = (x[n/2+1]-x[n/2]+1) * (y[n/2+1]-y[n/2]+1);
			cout << sum << endl;
		}
	}
}

C1. Guessing the Greatest (easy version)

比赛的时候一直没用二分做,呜呜我太菜了
附上TLE代码
最坏的情况假如每次查询到第二大的值就是下标就为r,则每次r=ans-1,相当于遍历n个元素,text3的时候就TLE啦。

#include <bits/stdc++.h>
using namespace std;

int ask(int l, int r)
{
	if (l >= r) return -1;
	cout << "? " << l << ' ' << r << endl;
	int ans;
	cin >> ans;
	return ans;
}

int main()
{
	int n;
	cin >> n;
	
	int l = 1, r = n;
	while (l < r)
	{
		int ans = ask(l, r);
		if (ask(l, ans) == ans) r = ans - 1;
		else l = ans + 1;
	}
	
	cout << "! " << l << endl;
}

二分,查询次数2*logn。
先查询[l, r]的第二大值,如果在[l, mid]中,查询[l, mid]的第二大值,如果二者相等,说明最大值在[l, mid]区间中,r=mid,反之l=mid+1。
第二种情况,第二大值在[mid+1, r]中,查询此区间第二大值,如果相等,l=mid+1,反之r=mid。

#include <bits/stdc++.h>
using namespace std;
int n;
int ask(int l, int r)
{
	if (l >= r) return -1;
	cout << "? " << l << ' ' << r << endl;
	int ans;
	cin >> ans;
	return ans;
}
int main()
{
	cin >> n;
	int l = 1, r = n;
	while(l < r)
	{
		int mid = l + r >> 1;
		int ans = ask(l, r);
		if (ans <= mid)
		{
			if (ask(l, mid) == ans) r = mid;
			else l = mid + 1; 
		}
		else 
		{
			if (ask(mid + 1, r) == ans) l = mid + 1;
			else r = mid;
		}
	}
	cout << "! " << l << endl;
}

C2. Guessing the Greatest (hard version)

也是二分,查询次数2+logn,先查询[l, r]的第二大值,然后查询[l, ans],如果相等r=ans-1,反之l=ans+1。然后采用C1的方法就行了。(要用到两个二分模板)

#include <bits/stdc++.h>
using namespace std;

int ask(int l, int r)
{
	if (l >= r) return -1;
	cout << "? " << l << ' ' << r << endl;
	int ans;
	cin >> ans;
	return ans;
}

int main()
{
	int n;
	cin >> n;
	
	int l = 1, r = n;
	int ans = ask(l, r);
	if (ask(l, ans) == ans)
	{
		r = ans - 1;
		while(l < r)
		{
			int mid = l + r + 1 >> 1;
			if (ask(mid, ans) == ans)  l = mid;
			else r = mid - 1;
		}
	}
	else 
	{
		l = ans + 1;
		while(l < r)
		{
			int mid = l + r >> 1;
			if (ask(ans, mid) == ans) r = mid;
			else l = mid + 1;
		}
	}
	
	cout << "! " << l << endl;
}

D. Max Median

在n长度的区间中,找长度大于等于k的区间中,最大的中位数
我们都知道无论n为奇偶,大于等于中位数的数的个数(包括本身)大于小于中位数的个数。
好家伙,这居然是二分。无需在意原数组,对[l, r](数的取值范围)二分查找最大中位数,大于等于mid的为1,小于的为-1,b[]存他们的前辍和。
因为只要大于等于k长度即可,因此我们从k+1到n遍历,求出最大区间和,如果mx>0,中位数可能时当前数,也可能时大于当前数的数,那么l=mid,反之r=mid-1,二分查找出来的数是大于0中的mx的最小值,我们可以证明只有查找到的数是原数组里的数,才能满足mx最小(n为偶数时mx为2,n为奇数时mx为1)。

#include <bits/stdc++.h>
using namespace std;

const int N=2e5+5;
int a[N], b[N];

int main()
{
	int n, k;
	cin >> n >> k;
	for (int i=1; i<=n; i ++ ) cin >> a[i];
	
	int l = 1, r = n;
	while (l < r)
	{
		int mid = l + r + 1 >> 1;
		for (int i=1; i<=n; i ++ )
		{
			if (a[i] >= mid) b[i] = 1;
			else b[i] = -1;
		 } 
		 for (int i=1; i<=n; i ++ ) b[i] += b[i-1];
		 int mx = b[k];
		 int mn = 0;
		 for (int i=k+1; i<=n; i ++ )
		 {
		 	mn = min(mn, b[i - k]);
		 	mx = max(mx, b[i] - mn);
		 }
		 if (mx > 0) l = mid;
		 else r = mid - 1;
	}
	cout << l << endl;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值