luogu P2519 [HAOI2011]problem a
题面传送门
这个东西不太好维护,考虑转化成\([a_i+1,n-b_i]\)这一区间中的人分数相同。
则只有选出一些区间,这些区间要么完全重合,要么完全不交,这些人才没有说谎。
显然有\(O(n^2)\)\(dp\)式\(dp_i=\min\limits_{j=1}^{i-1}{dp_j+1[(x_i==x_j\&\&y_i==y_j)||x_i>y_j]}\)
这个东西用树状数组随便搞就可以\(O(nlogn)\)了。
代码实现:
#include<cstdio>
#include<algorithm>
#define max(a,b) ((a)>(b)?(a):(b))
using namespace std;
int n,m,k,x,y,z,dp[100039],f[400039],head,now,maxn=1;
struct yyy{int x,y;}s[100039];
inline bool cmp(yyy x,yyy y){return x.x==y.x?x.y<y.y:x.x<y.x;}
inline int find(int x){int ans=0;while(x)ans=max(ans,f[x]),x-=x&-x;;return ans;}
inline void get(int x,int y){while(x<=n) f[x]=max(f[x],y),x+=x&-x;}
int main(){
// freopen("1.in","r",stdin);
register int i,j,h;
scanf("%d",&n);
for(i=1;i<=n;i++){
scanf("%d%d",&x,&y);
if(x+y<n)s[++head].x=x+1,s[head].y=n-y;
}
sort(s+1,s+head+1,cmp);
for(i=1;i<=head;i++){
now=0;//printf("%d\n",i);
for(j=i;j<=head;j++){
if(s[i].x!=s[j].x||s[i].y!=s[j].y) break;
now++;
}
if(now>s[i].y-s[i].x+1){
dp[i]=find(s[i].x-1)+1;
for(h=i+1;h<=i+s[i].y-s[i].x;h++)dp[h]=dp[h-1]+1;
get(s[h-1].y,dp[h-1]);
}
else{
dp[i]=find(s[i].x-1)+1;
for(h=i+1;h<j;h++)dp[h]=dp[h-1]+1;
get(s[h-1].y,dp[h-1]);
}
maxn=max(maxn,dp[h-1]);
i=h-1;
}
printf("%d\n",n-maxn);
}