codefroces 946G Almost Increasing Array

Description
给你一个长度为$n$的序列$A$.现在准许你删除任意一个数,删除之后需要修改最小的次数使序列单调递增。问最小次数。
$1≤n≤200000$
Examples
Input
5
5 4 3 2 1
Output
3
Input
5
1 2 8 9 5
Output
0

因为是修改形成递增,所以假设修改$l+1~r-1$,那么要求$a[r]-a[l]-1>=r-l-1$

于是有$a[r]-r>=a[l]-l$

于是就转化为求最长不下降子序列

因为可以删一个点,删掉的点的后面的值减去的位权-1

设$f[i][0/1]$为第i位,是否删了点

用二分优化,重新令$f[i][0/1]$表示长为i的序列末尾最小的数,是否删点

注意删了点的话位置会向前移,所以由$a[i]-i$变成$a[i]-i+1$

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<cmath>
 6 using namespace std;
 7 int inf=1e9,f[200005][2],a[200005],b[200005],n,tot,ans;
 8 int find(int x,int p)
 9 {
10   int l=1,r=n,as=0;
11   while (l<=r)
12     {
13       int mid=(l+r)/2;
14       if (f[mid][p]>x)as=mid,r=mid-1;
15       else l=mid+1;
16     }
17   return as;
18 }
19 int main()
20 {int i,tmp1,tmp2;
21   cin>>n;
22   for (i=1;i<=n;i++)
23     {
24       scanf("%d",&a[i]);
25       f[i][0]=f[i][1]=inf;
26     }
27   f[0][0]=f[0][1]=-inf;
28   for (i=2;i<=n;i++)
29     {
30       tmp1=find(a[i-1]-i+1,0);tmp2=find(a[i]-i+1,1);
31       f[tmp1][0]=a[i-1]-i+1;
32       f[tmp2][1]=a[i]-i+1;
33       f[tmp1][1]=min(f[tmp1][1],f[tmp1][0]);
34       ans=max(ans,max(tmp1,tmp2));
35     }
36   cout<<n-ans-1;
37 }

 

posted @ 2018-03-14 17:11  Z-Y-Y-S  阅读(217)  评论(0编辑  收藏  举报