bzoj2298 [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
思路: 这个题目可以转换为给你n个区间,每个区间都有一个价值v,从中选出若干个不相交的区间,使得价值之和最大。每个区间的价值在这里就是有几个重合的区间,如果重合的次数多于区间的长度,那么价值只能是区间的长度,否则就按照实际重合的长度统计。
例如,第一个的名次范围是3到6,第二个人的名字范围是3到6,那么3到6的重合次数就是2,3到6的区间的价值就是2。 明显的,我们选出的这些区间不能是相交的,否则肯定是矛盾的。 由于n有10万,我们可以贪心或者dp解决。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define rep(i,a,b) for(int i=a;i<=b;i++) 4 #define Rep(i,a,b) for(int i=a;i>=b;i--) 5 #define ms(i,a) memset(a,i,sizeof(a)) 6 #define gc() getchar() 7 template<class T>void read(T &x){ 8 x=0; char c=gc(); 9 while (!isdigit(c)) c=gc(); 10 while (isdigit(c)) x=x*10+(c^48),c=gc(); 11 } 12 int const N=100000+3; 13 struct seg{ 14 int x,y,num; 15 bool operator <(const seg & rhs) const { if(x!=rhs.x) return x<rhs.x; return y<rhs.y; } 16 }a[N]; 17 int n,m,f[N]; 18 int main(){ 19 read(n); 20 rep(i,1,n){ 21 int x,y; read(x); read(y); 22 if(x+y<n){ 23 m++; 24 a[m].x=x+1; 25 a[m].y=n-y; 26 } 27 } 28 sort(a+1,a+m+1); 29 int cnt=1; 30 a[1].num=1; 31 rep(i,2,m) 32 if(a[i].x==a[cnt].x && a[i].y==a[cnt].y) a[cnt].num++; 33 else cnt++,a[cnt]=a[i],a[cnt].num=1; 34 int k=1,r=1,v=0; 35 rep(i,1,cnt) if(a[i].num>a[i].y-a[i].x+1) a[i].num=a[i].y-a[i].x+1; 36 rep(i,1,n){ 37 f[i]=max(f[i],f[i-1]); 38 int num=0 ; 39 if(a[k].x!=i || k>cnt) continue; 40 while (a[k].x==i && k<=cnt ){ 41 while (r<i) v=max(v,f[r]),r++; 42 f[a[k].y]=max(f[a[k].y],v+a[k].num); 43 k++; 44 } 45 } 46 printf("%d\n",n-f[n]); 47 return 0; 48 }