bzoj 4985(二分+dp)

3 篇文章 0 订阅

把评分从小到大排序,在所有的评分中,二分出一个答案x,去验证x 是否合法;

dp[i] :i为最后一个数时,并且i>=x,前面需要添加的>=x的数个数;

如果dp[最后一个数]所需要添的>=x的数个数<=不知道位置的数的,那么合法;

dp[1-n]都是最初的状态;

如果i位置上的数<x,无论加多少个都不可能使它本身>=x,所以赋值为inf

如果i位置上的数>=x,它本身>=x,所以赋值为0;

如果i位置上的数未知,赋值为1;

然后就模拟,每次取队首前三个,用最小的两个数的和

如果两个数的和<inf说明有两个都是>=x的数,那么新的队尾一定也可以>=x;dp[++tail] = 两个数的和

如果两个数的和>=inf说明有两个都是<x的数,那么新的队尾一定也可以<x;dp[++tail] = inf(如果赋值成 两个数的和会加爆的)

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
int a[200000], b[200000],c[200000], n, m;
long long dp[600000]; 
int check(int x)
{
	memset(dp,0,sizeof(dp));
	int shu  = 0;
	for(int i = 1; i <= n - m; i++)
	{
		if(b[i] >= x) shu ++;
	}
	for(int i = 1;  i <= n; i++)
	{
		if(a[i] == 0) dp[i] = 1;
		else if(a[i] >= x) dp[i] = 0;
		else dp[i] = 1e9;
	}
	int head = 1, tail = n;
	while(head + 1< tail)
	{
		long long t = dp[head + 1] + dp[head] + dp[head + 2];
		long long ha = max(dp[head + 1], dp[head]);
		 ha = max(dp[head + 2], ha);
       if(t - ha > 1e9)dp[++tail] = 1e9;
	  else dp[++tail] = t - ha;
       head += 3;
	}
	if(dp[tail] > shu) return 0;
	return 1;
}
int main()
{
	cin >> n >> m;
	int cnt = 0;
	for(int i = 1; i <= m; i++)
	{
		int d, v;
		scanf("%d%d",&v,&d);
		a[d] = v;
		c[++cnt] = v;
	}
	for(int i = 1; i <= n - m; i++)
	{
    	scanf("%d",&b[i]);
		 c[++cnt] = b[i];
	}
	sort(1+c,1+c+cnt);
	int ans = 0,l = 1, r = cnt;
	while(l <= r)
	{
		int mid = (l + r) / 2;
		if(check(c[mid]) == 1)
		{
			l = mid + 1;
			ans = c[mid];
		}
		else r = mid - 1;
	}
	cout << ans;
	return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值