• Codeforces 946G. Almost Increasing Array


    Description

    给定序列 (A),求至少改变几个位置的值可以使得 (A) 去掉一个元素之后就变成单增的
    题面

    Solution

    朴素 (DP) 做法是,设 (f[i]) 表示前 (i) 个元素至少去掉的个数
    (f[i]=min(f[j]+j-i-1)),(a[i]-a[j]>=i-j)
    第二个条件其实就是 (a[i]-i>=a[j]-j)
    那么就是老套路:把 (a[i]) 变成 (a[i]-i)
    (DP)就变成了 (f[i]=min(f[j]+j-i-1)),(a[i]>=a[j])
    实际上就是 (n-) 最长不下降子序列

    这题还可以多去掉一个元素,考虑怎么做:
    实际上就是把去掉的元素之后的 (a[i]) 改为 (a[i]-(i-1)),也就是整体前移了一位

    所以我们需要枚举一个删除的元素,考虑分治优化
    我们发现这个(DP)是有传递性的,也就是说,用不同的 (mid) 更新的效果实际上是一样的,所以分治是可行的
    我们把 (mid) 两边的序列按 (a[i]) 排序,然后单调指针扫描一下就可以了

    #include<bits/stdc++.h>
    using namespace std;
    const int N=200010;
    int n,a[N],pre[N],suf[N],f[N],pos=0,ans=0;
    inline int find(int x){
    	int l=1,r=pos,mid,ret=0;
    	while(l<=r){
    		mid=(l+r)>>1;
    		if(x>=f[mid])ret=mid,l=mid+1;
    		else r=mid-1;
    	}
    	return ret;
    }
    struct node{
    	int w,v;
    	bool operator <(const node &p)const{return w<p.w;}
    }p[N],q[N];
    inline void solve(int l,int r){
    	int mid=(l+r)>>1;
    	if(l==mid || r==mid)return ;
    	solve(l,mid);solve(mid,r);
    	int L=0,R=0;
    	for(int i=l;i<mid;i++)p[++L]=(node){a[i],pre[i]};
    	for(int i=mid+1;i<=r;i++)q[++R]=(node){a[i]+1,suf[i]};
    	sort(p+1,p+L+1);sort(q+1,q+R+1);
    	for(int i=1,j=1,len=0;i<=R;i++){
    		while(j<=L && p[j].w<=q[i].w)len=max(p[j].v,len),j++;
    		ans=max(ans,len+q[i].v);
    	}
    }
    int main(){
      freopen("pp.in","r",stdin);
      freopen("pp.out","w",stdout);
      scanf("%d",&n);f[0]=-N;
      for(int i=1;i<=n;i++)scanf("%d",&a[i]),a[i]-=i;
      for(int i=1;i<=n;i++){
    	  if(a[i]>=f[pos])f[++pos]=a[i],pre[i]=pos;
    	  else{
    		  int t=find(a[i]);
    		  f[t+1]=min(f[t+1],a[i]);
    		  pre[i]=t+1;
    	  }
      }
      pos=0;
      for(int i=n;i>=1;i--){
    	  if(-a[i]>=f[pos])f[++pos]=-a[i],suf[i]=pos;
    	  else{
    		  int t=find(-a[i]);
    		  f[t+1]=min(f[t+1],-a[i]);
    		  suf[i]=t+1;
    	  }
      }
      solve(1,n);
      for(int i=1;i<=n;i++)ans=max(pre[i],ans),ans=max(suf[i],ans);
      cout<<max(n-ans-1,0)<<endl;
      return 0;
    }
    
    
  • 相关阅读:
    C语言面试题大汇总
    cocos2d-x的win32编译环境
    完美解决Android SDK Manager无法更新
    ADT离线安装教程
    Android开发环境搭建教程
    如何利用dex2jar反编译APK
    Eclipse与Android源码中ProGuard工具的使用
    Proguard语法及常用proguard.cfg代码段
    Android之ProGuard混淆器
    Nutch源码阅读进程2---Generate
  • 原文地址:https://www.cnblogs.com/Yuzao/p/8531345.html
Copyright © 2020-2023  润新知