[HAOI2011]Problem A
Description:
一次考试共有n个人参加,第i个人说:“有ai个人分数比我高,bi个人分数比我低。”问最少有几个人没有说真话(可能有相同的分数)
Hint:
\(n \le 10^5\)
Solution:
题目给的信息相当与\([a+1,n-b]\)的分数相等
于是问题转化为从一些带权区间中选出一些没有交集的区间的权值和最大
#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define ls p<<1
#define rs p<<1|1
using namespace std;
typedef long long ll;
const int mxn=1e5+5;
int n,m,cnt,hd[mxn];
inline int read() {
char c=getchar(); int x=0,f=1;
while(c>'9'||c<'0') {if(c=='-') f=-1;c=getchar();}
while(c<='9'&&c>='0') {x=(x<<3)+(x<<1)+(c&15);c=getchar();}
return x*f;
}
inline void chkmax(int &x,int y) {if(x<y) x=y;}
inline void chkmin(int &x,int y) {if(x>y) x=y;}
struct ed {
int to,nxt;
}t[mxn<<1];
inline void add(int u,int v) {
t[++cnt]=(ed) {v,hd[u]}; hd[u]=cnt;
}
int tot,f[mxn];
struct T {
int l,r,val;
}a[mxn],b[mxn];
int cmp(T x,T y) {
return x.l==y.l?x.r<y.r:x.l<y.l;
}
int cmp1(T x,T y) {
return x.r==y.r?x.l<y.l:x.r<y.r;
}
int find(int l,int r,int x) {
while(l<r) {
int mid=(l+r+1)>>1;
if(a[mid].r<x) l=mid; //利用答案的单调性进行二分查找优化
else r=mid-1;
}
return l;
}
int main()
{
n=read(); int sum=n;
for(int i=1;i<=n;++i) a[i].l=read()+1,a[i].r=n-read();
sort(a+1,a+n+1,cmp);
for(int i=1;i<=n;++i)
if(a[i].l<=a[i].r) b[++tot]=a[i];/*去除一定说谎的*/ n=0;
for(int i=1;i<=tot;++i)
if(i==1||b[i].l!=b[i-1].l||b[i].r!=b[i-1].r)
a[++n]=b[i],a[n].val=1;
else if(a[n].val<a[n].r-a[n].l+1) ++a[n].val; //去除一定说谎的
sort(a+1,a+n+1,cmp1); f[1]=a[1].val;
for(int i=2;i<=n;++i) {
int pos=find(1,i-1,a[i].l);
f[i]=max(f[i-1],f[pos]+a[i].val); //dp
}
printf("%d",sum-f[n]);
return 0;
}