题意:
题目大意:给出一个长度为 n 的序列,现在有 m 个位置被锁定,也就是无法进行操作,每次操作可以选择一个没有被锁定的位置,将其更改为任意数值,现在问最少进行多少次操作,可以使得整个序列变得严格递增
思路:
有个小技巧,看了大佬的博客才明白的,就是每一位都减去它的下标,这样判断起来,只需要判断锁住的元素是单调不下降的,就合法了,然后该题就转换成求k段操作数最少,由于每一段是独立的,那么考虑一段,有个结论最少操作数就是len-最长不下降子序列长度,那就分别求每一段就行了,加两个哨兵可以更有效的做题,然后在分别求每一段的时候也是不一样的,len=1的时候的数组是不能动的,最后一定要以a[r]结尾的最长不下降,lower_bound 和 upperbound把我搞糊涂了。。
#include<bits/stdc++.h>
using namespace std;
const int N=500010;
int d[N];
int n,m;
int a[N],b[N];
bool check()
{
for(int i=2;i<=m;i++)
{
if(a[b[i]]<a[b[i-1]])
return false;
}
return true;
}
int cal(int l,int r)
{
int len=1;
d[len]=a[l];
for(int i=l+1;i<=r;i++)
{
if(a[i]>=d[len]) d[++len]=a[i];
else
{
int pos=upper_bound(d+1,d+1+len,a[i])-d;
if(pos!=1)
d[pos]=a[i];
}
}
int pos=upper_bound(d+1,d+1+len,a[r])-d-1;
return (r-l+1)-pos;
}
int main()
{
// int a[100]={0,1,2};
//cout<<lower_bound(a,a+4,3)-a<<endl;
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>a[i],a[i]-=i;
for(int i=1;i<=m;i++)
cin>>b[i];
b[0]=0,b[m+1]=n+1;
a[0]=-0x3f3f3f3f,a[n+1]=0x3f3f3f3f;
if(!check())
return 0*puts("-1");
int res=0;
for(int i=1;i<=m+1;i++)
res+=cal(b[i-1],b[i]);
cout<<res<<endl;
return 0;
}