[luogu] P2519 [HAOI2011]problem a (贪心)

P2519 [HAOI2011]problem a

题目描述

一次考试共有n个人参加,第i个人说:“有ai个人分数比我高,bi个人分数比我低。”问最少有几个人没有说真话(可能有相同的分数)

输入输出格式

输入格式:

第一行一个整数n,接下来n行每行两个整数,第i+1行的两个整数分别代表ai、bi

输出格式:

一个整数,表示最少有几个人说谎

输入输出样例

输入样例#1: 复制

3
2 0
0 2
2 2

输出样例#1: 复制

1

说明

100%的数据满足: 1≤n≤100000 0≤ai、bi≤n

题解

本题因为过度巧妙引起极度不适。
看题十分钟。。。暴力都不会。
日常开题解。

我只想到了对于一个人,
\([a_i+1,n-b_i]\)内累计人数超过的这个区间的就不算了。
还有本身矛盾的就是\(a_i+b_i>=n\)
然后怎么做啊。。。
一看题解,做完了。。。
我们把人转为\([a_i+1,n-b_i]\)的区间以后,这个区间有一个价值,就是当前描述位于这个区间合法(有没有多于这个区间)的人数。
然后dp求一下第i个人时的最大值就可以了。

\(f[i]=max(f[i-1],f[next]+val);\)

Code

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<map>
#include<vector>
using namespace std;
const int N=1e6+5;
int n,f[N];
vector<int>q[N];
map<pair<int,int>,int>mp;

int read(){
	int x=0,w=1;char ch=getchar();
	while(ch>'9'||ch<'0'){if(ch=='-')w=-1;ch=getchar();}
	while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
	return x*w;
}

int main(){
	n=read();
	for(int i=1;i<=n;i++){
		int l=read(),r=read();
		l++;r=n-r;
		if(l>r)continue;
		if(++mp[make_pair(l,r)]==1)
			q[r].push_back(l);
	}
	for(int i=1;i<=n;i++){
		f[i]=f[i-1];
		for(int j=0;j<q[i].size();j++)
		f[i]=max(f[i],f[q[i][j]-1]+min(i-q[i][j]+1,mp[make_pair(q[i][j],i)]));
	}
	cout<<n-f[n]<<endl;
	return 0;	
} 
posted @ 2019-04-07 21:11  Epiphyllum_thief  阅读(126)  评论(0编辑  收藏  举报