Description
一次考试共有n个人参加,第i个人说:“有ai个人分数比我高,bi个人分数比我低。”问最少有几个人没有说真话(可能有相同的分数)
Input
第一行一个整数n,接下来n行每行两个整数,第i+1行的两个整数分别代表ai、bi
Output
一个整数,表示最少有几个人说谎
每个人的表述等价于排名[ai+1,n-bi]的人分数相同且区间外的人分数不同
将相同的区间合并并记录个数作为权值,若个数超过区间长度则以区间长度为准
于是问题转化为取一些互不相交的区间使权值和最大,可以dp解决,用树状数组优化可做到O(nlogn)
#include<cstdio> #include<algorithm> struct seg{ int l,r,t; }ss[100005]; inline bool operator<(const seg&a,const seg&b){ return a.r!=b.r?a.r<b.r:a.l<b.l; } int n,p=0; int bit[100005]; inline void maxs(int&a,int b){if(a<b)a=b;} inline void ins(int w,int x){ ++w; while(w<=n+1)maxs(bit[w],x),w+=w&-w; } inline int find(int w){ ++w; int ans=0; while(w)maxs(ans,bit[w]),w-=w&-w; return ans; } int main(){ scanf("%d",&n); for(int i=0,l,r;i<n;i++){ scanf("%d%d",&l,&r); ++l;r=n-r; if(l<=r)ss[p++]=(seg){l,r,1}; } std::sort(ss,ss+p); int p2=0; for(int i=1;i<p;i++){ if(ss[i].l==ss[p2].l&&ss[i].r==ss[p2].r)++ss[p2].t; else ss[++p2]=ss[i]; } p=p2+1; for(int i=0;i<p;i++){ int c=ss[i].r-ss[i].l+1; if(ss[i].t>c)ss[i].t=c; } int ans=0; for(int i=0;i<p;i++){ int c=ss[i].t+find(ss[i].l-1); maxs(ans,c); ins(ss[i].r,c); } printf("%d\n",n-ans); return 0; }