E. Make It Increasing(DP最长不下降子序列)

在这里插入图片描述

题意:一个数组a(长度为n),还有数组b(长度为k),其中数组b中存的是位置,在数组a中这些位置的数不可以改变,其余位置的数可以随意改变,问能否是a变成一个上升序列,能的话最小的操作次数是多少

首先判断一下能否使a变成上升序列(略)
然后将a划分为k+1个区间,每个区间单独计算
将每个区间处理一下
比如一段序列:2、3、5、7、8、6、10
每个数减去其相应的位置
然后序列变为:1、1、2、3、3、0、3
可以看出该序列的最长上升子序列为处理后的最长不下降子序列,其中该区间是被b数组固定的,因此该区间前后还有b数组固定的数,因此该区间的最长不下降子序列的值要大于等于a[b[i-1]]-1和a[b[i]]-(b[i]-b[i-1]+1

代码:

#include <bits/stdc++.h>
#define ll long long
#define IOS std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;

ll n,k,ans;
ll a[500005],b[500005];
ll c[500005],f[500005];
ll inf=0x3f3f3f3f3f3f3f;
void dp(ll st,ll en,ll x,ll y)
{
    
    
	ll cnt=0,val=2,ip=0,id=-1;
	for(int i=x;i<=y;i++)
	{
    
    
		c[++cnt]=a[i]-val;
		val++;
	}
	for(int i=1;i<=cnt;i++)
	{
    
    
		if(c[i]>=st&&c[i]<=en){
    
    id=i;break;}
	}
	if(id==-1){
    
    ans+=(y-x+1);return;}
	f[ip++]=c[id];
	for(int i=id+1;i<=cnt;i++)
	{
    
    
	    if(c[i]>en||c[i]<st){
    
    continue;}
		if(c[i]>=f[ip-1]){
    
    
			f[ip++]=c[i];
		}
		else{
    
    
			ll pos=upper_bound(f,f+ip,c[i])-f;
			f[pos]=c[i];
		}
	}
	ans+=(y-x+1-ip);
	return;
}
int main()
{
    
    
	scanf("%lld %lld",&n,&k);
	for(int i=1;i<=n;i++)
	{
    
    scanf("%lld",&a[i]);}
	for(int i=1;i<=k;i++)
	{
    
    scanf("%lld",&b[i]);}
	if(k==0)//特判k=0
	{
    
    
		ll ip=0;
		for(int i=1;i<=n;i++){
    
    c[i]=a[i]-i;}
		f[ip++]=c[1];
		for(int i=2;i<=n;i++)
		{
    
    
			if(c[i]>=f[ip-1])
			{
    
    f[ip++]=c[i];}
			else
			{
    
    
				ll pos=upper_bound(f,f+ip,c[i])-f;
				f[pos]=c[i];
			}
		}
		printf("%lld\n",n-ip);
		return 0;
	}
	ll flag=1;//判断结果是否为-1
	for(int i=2;i<=k;i++)
	{
    
    
		if(a[b[i]]<=a[b[i-1]]){
    
    flag=0;break;}
		if(b[i]-b[i-1]-1>a[b[i]]-a[b[i-1]]-1){
    
    flag=0;break;}
	}
	if(!flag){
    
    printf("-1\n");return 0;}
	for(int i=1;i<=k;i++)
	{
    
    
		if(i==1){
    
    
			ll st=-inf,en=a[b[i]]-b[i]-1;
			dp(st,en,1,b[i]-1);
		}
		else{
    
    
			ll st=a[b[i-1]]-1,en=a[b[i]]-(b[i]-b[i-1]+1);
			dp(st,en,b[i-1]+1,b[i]-1);
		}
	}
	dp(a[b[k]]-1,inf,b[k]+1,n);
	printf("%lld\n",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43781431/article/details/109365007