bzoj 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

 

题解:

很好想的题啊,题目也短短的,我喜欢..

考虑题目给的a,b的含义

如果a+b==n-1那么这个人的排名就固定了

反之 那么这个人就可以成为[a+1,n-b]中的任意一个排名....

还有一个关键就是 如果承认了一个人 就等于承认了[a+1,n-b]这个区间的人必须分数相等 且其他人不得与[a+1,n-b]的人相等

那么就可以转换成线段覆盖问题,f[i]=f[j]+1   (如果i,j不相交)

但是如果区间重合了 我们就可以累加,所以转化为f[i]=f[j]+min(val,r[i]-l[i]+1)  (val为和i重合的区间个数 但不得超过该区间大小)

最后树状数组存 f[j]+val 优化下即可

 

 1 #include <algorithm>
 2 #include <iostream>
 3 #include <cstdlib>
 4 #include <cstring>
 5 #include <cstdio>
 6 #include <cmath>
 7 using namespace std;
 8 const int N=100005;
 9 int n;
10 struct node{
11     int l,r,val;
12     bool operator <(const node &pp){
13         if(pp.r!=r)return r<pp.r;
14         return l<pp.l;
15     }
16 }a[N];
17 int Tree[N];
18 void updata(int sta,int x){
19     for(int i=sta;i<=n;i+=(i&(-i)))
20         if(Tree[i]<x)Tree[i]=x;
21 }
22 int query(int sta){
23     int ret=0;
24     for(int i=sta;i>=1;i-=(i&(-i)))
25         if(Tree[i]>ret)ret=Tree[i];
26     return ret;
27 }
28 void work()
29 {
30     int x,y,m=0;
31     scanf("%d",&n);
32     for(int i=1;i<=n;i++){
33         scanf("%d%d",&x,&y);
34         x++;y=n-y;
35         if(x>y)continue;
36         a[++m].l=x;a[m].r=y;a[m].val=0;
37     }
38     sort(a+1,a+m+1);
39     int tot=0,t,ret=0;
40     for(int i=1;i<=m;i++){
41         if(a[tot].l==a[i].l && a[tot].r==a[i].r)a[tot].val++;
42         else a[++tot]=a[i],a[tot].val=1;
43     }
44     for(int i=1;i<=tot;i++)
45         if(a[i].r-a[i].l+1<a[i].val)a[i].val=a[i].r-a[i].l+1;
46   updata(a[1].r,a[1].val);
47     for(int i=2;i<=tot;i++){
48         t=query(a[i].l-1)+a[i].val;
49         if(t>ret)ret=t;
50         updata(a[i].r,t);
51     }
52     printf("%d\n",n-ret);
53 }
54 
55 int main()
56 {
57     work();
58     return 0;
59 }

 

posted @ 2017-08-15 00:14  PIPIBoss  阅读(264)  评论(0编辑  收藏  举报