题目链接:点击进入
题意
一个长度为 n 的序列,有 k 个位置被锁定(无法改变),你每次操作可以选择一个没有被锁定的位置,将其更改为任意数值,问最少进行多少次操作,可以使得整个序列变成严格递增的
思路
这个 k 个位置相当于把整个序列分成了 k + 1 个部分,相当于求 k + 1 个确定首尾的最长不下降子序列(然后把这 k + 1 个最长子序列的长度加起来就是整个序列的包含指定元素的最长严格递增子序列的长度)
(开头对a数组偏移了,不懂的可以查看)
代码
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn=1e6+10;
int k,n,a[maxn],b[maxn],flag,p[maxn],len;
int look(int l,int r)
{
int len=1;
p[len]=a[l];
for(int i=l+1;i<=r;i++)
{
if(a[i]>=p[len]) p[++len]=a[i];
else
{
int pos=upper_bound(p+1,p+len+1,a[i])-p;
if(pos!=1) p[pos]=a[i];
}
}
int pos=upper_bound(p+1,p+len+1,a[r])-p;
return r-l-pos+2;
}
int main()
{
ios::sync_with_stdio(false);
cin>>n>>k;
a[0]=-INF,a[n+1]=INF;
for(int i=1;i<=n;i++) cin>>a[i],a[i]-=i;
b[0]=0,b[k+1]=n+1;
for(int i=1;i<=k;i++)
{
cin>>b[i];
if(a[b[i-1]]>a[b[i]]) flag=1;
}
if(flag) cout<<"-1"<<endl;
else
{
int ans=0;
for(int i=0;i<k+1;i++)
ans+=look(b[i],b[i+1]);
cout<<ans<<endl;
}
return 0;
}

本文介绍了一种算法问题,即如何通过最少的操作使一个序列变为严格递增,并给出了详细的实现思路与C++代码示例。
1万+

被折叠的 条评论
为什么被折叠?



