在做这一题之前先看一道题:
给的一个长度为n的序列a,求最少需要改变a的数量,使得a序列非严格递增。
显然结果为:n-LIS,(因为最后一定有些数是不变的,我们让不变的数尽量长,则必须让不变的数满足最终序列的性质即:非递减)
如果把非严格改成严格递增呢?
我们依然用上面的思路:让不变的序列尽量长,即满足最终序列,最终序列是严格递增序列,由于是整数,则对于:j>i,必须满足a[j]>a[i].且a[j]-a[i]>=j-i. 这样才能保证中间变化的数有解。
为了方便我们对上面的式子变化一下:a[j]-j>=a[i]-i. 为了方便: 我们刚开始让a[i]-=i,最终得到的序列就只需要满足j>i,a[j]>a[i],即可,即:满足a序列非严格递增即可。这就回到了第一个问题,直接求即可。
知道上面的经典例题后,我们来看这道题就非常简单了:
首先比较显然的思路:
对于每段b[i-1],b[i],我们把它看成一个区间,求一次结果。最后累加即可。若有一个区间a[R]-a[L]>R-L,则说明无法构造成功,输出-1即可。为了方便可在首尾加上两个哨兵节点。
另外:对于每段区间L,R。我们求得是R-L-1-LIS。
其中LIS是必须要包括a[L],和a[R]的。所以在nlogn求LIS的过程中我们需要改动一下:
首先我们要对nlogn求LIS的过程比较熟练:
dp[i]表示长度为i的非严格递增子序列结尾最小值为多少。
每次从前往后遍历,若二分到最后一个一个大于dp的位置tp,然后插到其后面,改变的dp[tp+1]的值,表示当前数接在长度为tp结尾为dp[tp]的LIS后面可以更新长度为tp+1的LIS的结尾值。稍微分析下可知,只需要改变这一个位置。其他的长度,要么无法改变,要么改变了不是最优解。
那么这题要怎么办呢?
我们可以强制让组成LIS的每个元素值必须大于等于a[L],小于等于a[R],这样刚好能保证第一个和最后一个必选。。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define re register
#define ls (o<<1)
#define rs (o<<1|1)
//#define m (l+r)/2
#define pb push_back
typedef pair<int,int> pii;
const double PI= acos(-1.0);
const int M = 5e5+7;
/*
int head[M],cnt=1;
void init(int n){cnt=1;for(int i=0;i<=n;i++)head[i]=0;}
struct EDGE{int to,nxt,w;}ee[M*2];
void add(int x,int y,int w){ee[++cnt].nxt=head[x],ee[cnt].w=w,ee[cnt].to=y,head[x]=cnt;}
*/
int b[M],a[M],dp[M];
int n,k;
int gao(int L,int R){
int up=1;
for(int i=0;i<=R-L+1;i++)dp[i]=1e9+7;
dp[1]=a[L];
for(int i=L+1;i<=R;i++){
if(a[i]>a[R])continue;//必须保证最后一个必选
int l=1,r=up,tp=0;
while(l<=r){
int m=(l+r)/2;
if(dp[m]<=a[i])l=m+1,tp=m;
else r=m-1;
}
if(tp==0)continue;//保证L不会被更新,即L必选
dp[tp+1]=a[i];
up=max(up,tp+1);
}
// cout<<" - "<<L<<" "<<R<<" "<<up<<" = "<<R-L+1-up<<endl;
return R-L+1-up;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n>>k;
for(int i=1;i<=n;i++){
cin>>a[i];
a[i]-=i;
}
/* for(int i=1;i<=n;i++){
cout<<a[i]<<" ";
}
cout<<endl;*/
for(int i=1;i<=k;i++)cin>>b[i];
int ans=0;
b[k+1]=n+1;
b[0]=0;
a[n+1]=1e9+1;
a[0]=-1e9-1;
for(int i=1;i<=k+1;i++){
if(a[b[i]]<a[b[i-1]]){
cout<<-1<<endl;
return 0;
}
// cout<<i<<" "<<ans<<endl;
ans+=gao(b[i-1],b[i]);
}
cout<<ans<<endl;
return 0;
}