题意:给出一个长度为n的序列,k个位置,代表序列里这些位置上的数是固定的。每次可以修改序列里没被固定的一个数,问最少几次修改可以使得整个序列变成严格递增的,或者不可能。


两个小结论

1、把一个序列A变成非严格单调递增(单调不下降的),至少需要修改的数个数为序列A的总长度减去A的最长不下降子序列长度。
2、把一个序列变成严格单调递增的,至少需要修改的数个数,构造序列B[i]=A[i]-i,答案为序列总长度减去B的最长不下降子序列长度。

思路:这道题如果把固定一些数这个条件去掉的话就是看成上面结论2一样的问题了,但是仔细观察可以发现k个数将整个序列分为了k+1个部分,因为k个数是固定的,所以这k+1个部分其实是互不影响的,可以把他们拿出来单独做,就变成和上面结论2里一样的问题了。唯一有区别的是,在求解最长不下降子序列的时候,首位和末位是被固定的。所以在使用二分法求解时要一些变化。具体实现就是先令 d[1] = a[l-1] ,且 d[1] 不允许修改,按照正常的流程计算完 [l,r] 这段区间的 lis,然后找到小于等于a[r+1]的最大位置,此时的长度就是答案了。可以在整个序列的首尾设置一些哨兵元素这样就不需要特判了。

AC代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define X first
#define Y second
#define pb push_back
#define pll pair<ll, ll>
#define pli pair<ll, int>
#define pii pair<int,int>
#define New_Time srand((unsigned)time(NULL))
inline ll gcd(ll a, ll b) { while (b != 0) { ll c = a % b; a = b; b = c; }return a < 0 ? -a : a; }
inline ll lowbit(ll x) { return x & (-x); }
//int head[2000010], Edge_Num;
//struct Edge { int to, next; ll w; }e[4000010];
//inline void ade(int x, int y, ll w) { e[++Edge_Num] = { y,head[x],w }; head[x] = Edge_Num; }
//inline void G_init(int n) { memset(head, 0, sizeof(int) * (n + 100)); Edge_Num = 0; }
int dir[8][2] = { {-1,0},{0,-1},{-1,-1},{1,-1},{1,0},{0,1},{1,1},{-1,1} };
const long double PI = 3.14159265358979323846;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
inline ll rd() {
    ll x = 0; bool f = 1; char ch = getchar();
    while (ch < '0' || ch>'9') { if (ch == '-')f = 0; ch = getchar(); }
    while (ch >= '0' && ch <= '9') { x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar(); }
    return f ? x : -x;
}
const double eps = 1e-8;
const ll mod = 1e9 + 7;
const int M = 1e6 + 10;
const int N = 1e6 + 10;
int a[N], b[N];
int n, k;
vector<int>lis;
int gao(int l, int r) {
    if (b[r + 1] - b[l - 1] - 1 < r - l + 1)return -1;
    lis.clear();
    lis.pb(a[l - 1]);
    for (int i = l; i <= r; i++) {
        if (a[i] >= lis.back())lis.pb(a[i]);
        else {
            int p = upper_bound(lis.begin(), lis.end(), a[i]) - lis.begin();
            if (p == 0)continue;
            lis[p] = a[i];
        }
    }
    int pos = upper_bound(lis.begin(), lis.end(), a[r + 1]) - lis.begin() + 1;
    int len = (r + 1) - (l - 1) + 1;
    return len - pos;
}
bool check(int l, int r) {
    for (int i = l; i < r; i++) {
        if (b[i] >= b[i + 1])return 0;
    }
    return 1;
}
void solve() {
    n = rd(), k = rd();
    for (int i = 1; i <= n; i++) {
        b[i] = a[i] = rd();
        a[i] -= i;
    }

    b[0] = a[0] = -inf;
    b[n + 1] = a[n + 1] = inf;
    for (int i = 1; i <= k; i++) {
        vis[rd()] = 1;
    }
    int l = 0, r = 0;
    for (int i = 1; i <= n; i++) {
        if (vis[i] && (i == 1 || !vis[i - 1])) {
            l = i;
        }
        if (vis[i] && (i == n || !vis[i + 1])) {
            r = i;
            if (!check(l, r)) {
                puts("-1");
                return;
            }
        }
    }
    l = 0, r = 0;
    int ans = 0;
    for (int i = 1; i <= n; i++) {
        if (!vis[i] && (i == 1 || vis[i - 1])) {
            l = i;
        }
        if (!vis[i] && (i == n || vis[i + 1])) {
            r = i;
            int x = gao(l, r);
            if (x == -1) {
                puts("-1");
                return;
            }
            ans += x;
        }
    }
    cout << ans << endl;
}
int main() {
    int _T = 1;
    //_T = rd();
    while (_T--)solve();
}