[NESCAFE27] 探险队
题目描述
N个探险家组队去探索神秘的Nescafe之塔。在路上有个记者问每个探险家参加过的探险活动的数目,而探险家们都不愿意告诉他。于是这个记者得到的回答都是“有A个探险家参过的探险活动比我多,而B个探险家参加过的探险活动比我少。”当然并不一定所有的探险家都说了实话。现在这个杯具的记者想请你帮助他计算至少有多少个探险家说了谎?
输入格式
第一行是一个正整数N,表示探险队的人数。之后N行每行两个整数A和B,表示一个探险家的答案。
输出格式
输出一个整数表示答案,即至少有多少人说了谎。
样例输入
3
2 0
0 2
2 2
样例输出
1
数据范围与约定
对于30%的数据,满足1≤N≤1000。对于100%的数据,满足1≤A, B≤N≤100000。
思路:
dp
求加权的最多区间不重叠覆盖数
把N个人想象成一条长度为N的数轴
那么根据每个人前面的人的个数和后面的人的个数,我们可以确定那个人的位置范围
而很显然每一个人的位置范围中的人一定和自己参加过的探险活动次数相同,所以说如果两个人的位置范围部分重合(不完全重合),那么就以为这这两个人中有一个在说假话。
而当两个人的位置范围完全重合时,说明他们去过的探险活动次数可能相等。这时候我们可以把它合并为一个位置范围。
但是当然,一个从l到r的范围最多合并r-l次,就是说一个[l,r]最多代表l-r+1个人。
那么如果一个[l,r]重复了>l-r+1次,那么也是有人说谎。对于这种情况我一开始的想法是对于每一个多出l-r+1的[l,r]我把他看做一个独立的[l,r],但是后来发现多出来的完全不需要加入dp都可以。不过我程序也懒得改了。
然后就是dp计算长度为N的数轴上最多不重叠地放多少个位置范围(对于合并过的位置范围,他的权值是max{l-r+1,该位置范围出现过的次数})。
我只想到了用数据结构优化到nlogn的做法,不过后来知道这个dp的过程可以在O(n)的时间内完成,不过也懒得再改了(还是我太菜了)
Code:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 #define MAXN 100010 7 struct Node{ 8 int l,r; 9 int val,addval; 10 Node(){} 11 }T[MAXN<<2]; 12 int l[MAXN],r[MAXN],tmp[MAXN],ord[MAXN],num[MAXN]; 13 int i,j,k,m,n,cnt,x,y,val,temp; 14 char readc; 15 void build(int ro,int l,int r){ 16 T[ro].l=l,T[ro].r=r; 17 T[ro].val=T[ro].addval=0; 18 if(l==r){ 19 return ; 20 } 21 int mid=(l+r)>>1; 22 build(ro<<1,l,mid); 23 build((ro<<1)+1,mid+1,r); 24 } 25 void pushdown(int ro){ 26 if(T[ro].addval){ 27 int tmp=T[ro].addval; 28 T[ro<<1].val=max(T[ro<<1].val,tmp); T[(ro<<1)+1].val=max(T[(ro<<1)+1].val,tmp); 29 T[ro<<1].addval=max(T[ro<<1].addval,tmp); T[(ro<<1)+1].addval=max(T[(ro<<1)+1].addval,tmp); 30 T[ro].addval=0; 31 } 32 } 33 void update(int ro,int nl,int nr,int sl,int sr,int addval){ 34 if(sr<nl||sl>nr) return; 35 if(sl<=nl&&sr>=nr){ 36 T[ro].val=max(T[ro].val,addval); 37 T[ro].addval=max(T[ro].addval,addval); 38 return; 39 } 40 pushdown(ro); 41 int mid=(nl+nr)>>1; 42 update(ro<<1,nl,mid,sl,sr,addval); 43 update((ro<<1)+1,mid+1,nr,sl,sr,addval); 44 T[ro].val=max(T[ro].val,T[ro<<1].val); 45 T[ro].val=max(T[ro].val,T[(ro<<1)+1].val); 46 } 47 int query(int ro,int nl,int nr,int ql,int qr){ 48 if(qr<nl||ql>nr) return 0; 49 if(ql<=nl&&qr>=nr) return T[ro].val; 50 pushdown(ro); 51 int mid=(nl+nr)>>1; 52 return max(query(ro<<1,nl,mid,ql,qr),query((ro<<1)+1,mid+1,nr,ql,qr)); 53 } 54 bool CMP(const int &a,const int &b){ 55 if(r[a]<r[b]){ 56 return true; 57 }else{ 58 if(r[a]==r[b]){ 59 if(l[a]<l[b]) return true; 60 } 61 } 62 return false; 63 } 64 void read(int &n){ 65 while((readc=getchar())&&(readc<48||readc>57)); 66 n=readc-48; 67 while((readc=getchar())&&(readc>=48&&readc<=57)) n=n*10+readc-48; 68 } 69 int main(){ 70 freopen("explore.in","r",stdin); 71 freopen("explore.out","w",stdout); 72 read(n); 73 for(i=1;i<=n;i++){ 74 read(x),read(y); 75 l[i]=x+1; 76 r[i]=n-y; 77 tmp[i]=i; 78 } 79 sort(tmp+1,tmp+n+1,CMP); 80 cnt=0; val=0; 81 tmp[0]=0,l[0]=r[0]=0; 82 for(i=1;i<=n;i++){ 83 if(l[tmp[i]]>r[tmp[i]]) continue; 84 if(l[tmp[i]]<=0||l[tmp[i]]>n||r[tmp[i]]<=0||r[tmp[i]]>n) continue; 85 if(l[tmp[i]]!=l[ord[cnt]]||r[tmp[i]]!=r[ord[cnt]]){ 86 ord[++cnt]=tmp[i]; 87 val=r[tmp[i]]-l[tmp[i]]; 88 num[cnt]=1; 89 }else{ 90 if(val){ 91 val--; 92 num[cnt]++; 93 }else{ 94 ord[++cnt]=tmp[i]; 95 num[cnt]=num[cnt-1]; 96 } 97 } 98 } 99 build(1,1,n); 100 for(i=1;i<=cnt;i++){ 101 temp=query(1,1,n,1,l[ord[i]]-1); 102 temp+=num[i]; 103 update(1,1,n,r[ord[i]],r[ord[i]],temp); 104 } 105 printf("%d\n",n-query(1,1,n,1,n)); 106 return 0; 107 }