bzoj 2298: [HAOI2011]problem a
2298: [HAOI2011]problem a
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
ACTY真大神!!!
——————————以下题解————————————
输入n个x,y,即表示有x个人分数比i高,y个人分数比i低,那么有n-x-y个人分数和i一样
我们把i看作一个序列中的第x+1个人,前面的人都比他大,x+1~n-y之间的人分数和他一样
那么题目可以转化为给出n条线段,从中能挑出的最多的互不重叠的线段数即为最多的正确人数
至于这么求有很多方法,我还是喜欢DP。。。。
#include<stdio.h> #include<iostream> #include<algorithm> #include<string.h> using namespace std; struct node { int a,b; }p[100005]; int n,i,j,k,s,x,y,a[100005],h[100005],l[100005],r[100005],f[100005]; bool cmp(const node&x,const node&y) { if(x.b!=y.b) return x.b<y.b; return x.a<y.a; } int main() { scanf("%d",&n); k=0; for(i=1;i<=n;i++) { scanf("%d%d",&x,&y); if(x+y>=n) continue; k++; p[k].a=x+1; p[k].b=n-y; } sort(p+1,p+k+1,cmp); s=0; for(i=1;i<=k;i++) { if(p[i].a!=p[i-1].a||p[i].b!=p[i-1].b) s++; h[s]++; h[s]=min(h[s],p[i].b-p[i].a+1); l[s]=p[i].a; r[s]=p[i].b; } j=1; for(i=1;i<=n;i++) { f[i]=f[i-1]; while(j<=s&&r[j]==i) { f[i]=max(f[i],f[l[j]-1]+h[j]); j++; } } cout<<n-f[n]; return 0; }
一念起,天涯咫尺; 一念灭,咫尺天涯。