2298: [HAOI2011]problem a
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 1150 Solved: 557
[ Submit][ Status][ Discuss]
Description
一次考试共有n个人参加,第i个人说:“有ai个人分数比我高,bi个人分数比我低。”问最少有几个人没有说真话(可能有相同的分数)
Input
第一行一个整数n,接下来n行每行两个整数,第i+1行的两个整数分别代表ai、bi
Output
一个整数,表示最少有几个人说谎
Sample Input
3
2 0
0 2
2 2
2 0
0 2
2 2
Sample Output
1
HINT
100%的数据满足: 1≤n≤100000 0≤ai、bi≤n
Source
如果把所有学生的分数从小到大排好,那么第i个人说的话,等价于ai+1 ~ n-bi的人的成绩相等
这样,每个人说的话就可以看做一段区间,选出一个集合的人都说的是真话
那么这个集合的任意区间不相交,经典贪心了
然而这样做是错的。。。区间不相交,但是可以重叠
所以要类似dp一样去做,注意每段区间都有一个选择的上限。。。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn = 1E5 + 10;
struct data{
int L,R; data(){}
data(int L,int R): L(L),R(R){}
bool operator < (const data &b) const
{
if (R < b.R) return 1;
if (R > b.R) return 0;
return L < b.L;
}
bool operator == (const data &b) const
{
return L == b.L && R == b.R;
}
}D[maxn];
struct d2{
int L,Num; d2(){}
d2(int L,int Num): L(L),Num(Num){}
};
int n,cur,f[maxn],g[maxn];
vector <d2> v[maxn];
int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
#endif
cin >> n; int tot = 0;
for (int i = 1; i <= n; i++)
{
int x,y; scanf("%d%d",&x,&y);
if (x + y > n - 1) continue;
D[++tot] = data(x + 1,n - y);
}
sort(D + 1,D + tot + 1); g[1] = cur = 1;
for (int i = 2; i <= tot; i++)
if (D[i] == D[i-1])
{
if(g[cur] < D[i].R - D[i].L + 1) ++g[cur];
}
else D[++cur] = D[i],g[cur] = 1;
for (int i = 1; i <= cur; i++)
v[D[i].R].push_back(d2(D[i].L,g[i]));
for (int i = 1; i <= n; i++)
{
for (int j = 0; j < v[i].size(); j++)
{
d2 k = v[i][j];
f[i] = max(f[i],f[k.L-1] + k.Num);
}
f[i] = max(f[i],f[i-1]);
}
cout << n - f[n];
return 0;
}