• codeforces 1437 E. Make It Increasing (最长上升子序列)


    题目链接:https://codeforces.com/contest/1437/problem/E

    我们发现,每个不能改的位置之间的块是互不影响的
    所以我们考虑单独计算每个块内的答案

    对于每个块,如果元素小于边界(左右两边不能修改的元素大小),那么是必须要修改的,
    剩下的元素,我们要修改尽量少的元素
    没错,就是序列长度减去最长上升子序列的数量

    然而还有一个问题,最长上升子序列的某两个元素大小可能是相邻的,
    但是对应到原序列中,可能这两个元素之间可能还有别的元素,这样就无法修改中间元素了

    这里有一个小trick(看题解才明白): 如果最后 (a[i]) 是严格单调增的,那么 (a[i] - i) 一定是不降的,
    所以可以令 (c[i] = a[i] - i),去求解 (c[i]) 的最长不降子序列,这样就可以保证选出的最长上升子序列之间的元素肯定可以改变

    最后再判断一下什么时候无解就好了
    时间复杂度(O(nlogn))

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<cmath>
    #include<stack>
    #include<queue>
    using namespace std;
    typedef long long ll;
    
    const int maxn = 500010;
    
    int n,k,cnt = 0; int inf; int ans;
    int a[maxn],b[maxn],c[maxn],d[maxn],dp[maxn],g[maxn];
    
    void DP(int l,int r){
    	if(r<l) return;
    	for(int i=l;i<=r;++i){
    		if(c[i] <= c[r+1] && c[i] >= c[l-1]){
    			int pos = upper_bound(dp + l, dp + r, c[i]) - dp;
    			dp[pos] = c[i];	
    		} 
    	}
    	int flag = 0;
    	for(int i=r;i>=l;--i){
    		if(dp[i] != inf){
    			ans += (r - l + 1) - (i - l + 1);
    			flag = 1;
    			break;
    		}
    	}
    	if(!flag) ans += r-l+1;
    }
    
    ll read(){ ll s=0,f=1; char ch=getchar(); while(ch<'0' || ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0' && ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f; }
    
    int main(){
    	ans = 0;
    	memset(dp,0x3f,sizeof(dp));
    	inf = dp[0];
    
    	dp[0] = -inf;
    	int flag = 0;
    	n = read(), k = read();
    	for(int i=1;i<=n;++i){
    		a[i] = read();
    		c[i] = a[i] - i;
    	}
    	
    	c[0] = -inf; c[n+1] = inf;
    	
    	for(int i=1;i<=k;++i){
    		b[i] = read();
    		d[++cnt] = a[b[i]];
    	}
    	
    	for(int i=1;i<=cnt;++i){
    		int pos = lower_bound(dp + 1, dp + cnt, d[i]) - dp;
    		dp[pos] = d[i];
    	}
    	if(dp[cnt] == inf){
    		printf("-1
    ");
    	}
    	else{
    		int ff = 0;
    		memset(dp,0x3f,sizeof(dp));
    		dp[0] = -inf;
    		
    		for(int i=1;i<=k;++i){
    			DP(b[i-1]+1,b[i]-1);
    			if(i > 1 && b[i] - b[i-1] - 1 > 0 && b[i] - b[i-1] - 1 > a[b[i]] - a[b[i-1]] - 1){
    				ff = 1;
    				printf("-1
    ");
    				break;
    			}
    		}
    		if(b[k] <= n - 1) DP(b[k]+1,n);
    		if(!ff) printf("%d
    ",ans);
    	}
    	
    	return 0;
    }
    
  • 相关阅读:
    supervisor 简单使用
    golang的表格驱动测试
    golang和python的二进制转换
    django-rest-framework-jwt的使用
    threading.local在flask中的用法
    分布式的两种算法
    第24课
    Mock以及Mockito的使用
    java下使用chromedriver获取访问页面状态码
    Mockito:一个强大的用于Java开发的模拟测试框架
  • 原文地址:https://www.cnblogs.com/tuchen/p/13894375.html
Copyright © 2020-2023  润新知