BZOJ 4985: 评分 二分答案 dp判定

4985: 评分

Time Limit: 10 Sec  Memory Limit: 64 MB
Submit: 46  Solved: 34
[Submit][Status][Discuss]

Description

Lj最近参加一个选秀比赛,有N个评委参加了这次评分,N是奇数。评委编号为1到N。每位评委给Lj打的分数是一个整数,评委i(1 ≦ i ≦ N)的打分为Di。这次采用了一种创新的方法计算最后得分,计算规则是:最初N位评委排成一排,检查队伍排头的3位评委的评分,去掉一个最高分和一个最低分,剩下的一个评委移动到队伍最后,反复执行以上操作,直到队伍中的评委只剩一位,那么这个评委的打分就是Lj的最后得分。由于有的评委年纪比较大了,不记得自己的位置了,现在有M(1 ≦ M ≦ N - 2)个评委很快找到了自己的位置,剩下的N-M人找不到位置了,需要给他们重新安排位置。由于Lj希望自己的得分尽可能高。请你帮忙计算出LJ最后得分可能的最大值。

Input

第一行为整数N和M,用空格分隔。表示有N位评委,其中M人的初始排列位置已经确定。
接下来M行中第i行(1 ≦ i ≦ M)为两个整数Di和Pi,用空格分隔。
表示第i位评委的评分为Di,初始排列位置为队伍排头开始的第Pi位。
接下来N-M行中第i行(1 ≦ i ≦ N ? M)为整数Di+M,表示评委(i+M)的评分为Di+M。
3 ≦ N ≦ 99 999,
1 ≦ M ≦ N - 2,
1 ≦ Di ≦ 109 (1 ≦ i ≦ N),
1 ≦ Pi ≦ N (1 ≦ i ≦ M),
Pi != Pj (1 ≦ i < j ≦ M)。

Output

 输出一行,为1个整数,表示LJ得分的最大值。

Sample Input

7 3
5 2
5 5
8 6
6
2
8
9

Sample Output

8
//最高得分的评分排列:2, 5, 6, 8, 5, 8, 9


感觉这个题不是很好想到

翻了题解。。。

二分答案 然后用dp判定

怎么判定呢

设f(i)表示把令i位置的值>=二分答案x时,最少需要几个额外的(固定的)>=x的数在这之前为他挡枪

之后直接模拟删除过程,并dp转移就好了

D_n-m~D_n是可以随便放的所以他们是可以有的额外的数

然后求解出最后位置所需要的数,比较是否够用就可以了

最开始1~n每个位置i

若不确定

则f(i)=1 因为需要放一个>=x的数

若确定

若d[i]>=x f(i)=0 因为已经>=x不用多余的数来挡枪

否则f(i)=inf 无论如何也不能比>=x

之后每个位置由目前最前面的三个转移过来

不妨设他们的dp值为x,y,z

则转移方程为f(i)=min(x+y,x+z,y+z,inf)


#include<cmath>
#include<ctime>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<string>
#include<bitset>
#include<queue>
#include<set>
#include<map>
using namespace std;

inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch<='9'&&ch>='0'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
	return x*f;
}
void print(int x)
{if(x<0)putchar('-'),x=-x;if(x>=10)print(x/10);putchar(x%10+'0');}

const int N=100100,inf=0X3f3f3f3f;

int n,m,a[N],b[N];

int q[N<<1];

inline bool check(int val)
{
	register int i,tmp=0,head=0,tail=0,x,y,z;
	for(i=1;i<=n-m;++i)tmp+=(b[i]>=val);
	for(i=1;i<=n;++i)
	{
		if(!a[i])q[tail++]=1;
		else if(a[i]>=val)q[tail++]=0;
		else q[tail++]=inf;
	}
	while(tail>head+1)
	{
		x=q[head++];y=q[head++];z=q[head++];
		q[tail++]=min(min(x+y,x+z),min(y+z,inf));
	}
	return q[head]<=tmp;
}

int main()
{
	n=read();m=read();
	register int i,l=1,r=int(1e9),mid,x,y;
	for(i=1;i<=m;++i)
	{
		x=read();y=read();
		a[y]=x;
	}
	for(i=1;i<=n-m;++i)b[i]=read();
	while(l<=r)
	{
		mid=(l+r)>>1;
		check(mid)?l=mid+1:r=mid-1;
	}
	print(l-1);puts("");
	return 0;
}
/*
7 3
5 2
5 5
8 6
6
2
8
9

8
*/

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值