• #背包#nssl 1488 上升子序列


    题目

    给一个长度为(n)的数组(a)。试将其划分为两个严格上升子序列,并使其长度差最小。


    分析

    (max([1,i])<min([i+1,n]))时显然两个区间互不影响,把(i)视为分界点
    若相邻的两个分界点(i,j)所组成的区间([isim j])如果合法只有一种划分方法
    所以把合法区间贡献扔入背包里搞一搞就可以了


    代码

    #include <cstdio>
    #include <cctype>
    #include <bitset> 
    #define rr register
    using namespace std;
    const int N=100011; bitset<N>dp;
    int n,mx[N],mn[N],a[N],flag,ans,las;
    inline signed iut(){
    	rr int ans=0; rr char c=getchar();
    	while (!isdigit(c)) c=getchar();
    	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
    	return ans;
    }
    inline void print(int ans){
    	if (ans>9) print(ans/10);
    	putchar(ans%10+48);
    }
    inline bool check(int l,int r){
    	rr int fi=0,se=0,TOT=0;
    	for (rr int i=l;i<=r;++i)
    	if (fi<a[i]) fi=a[i],++TOT;
    	    else if (se<a[i]) se=a[i];
    	        else return 0;
    	dp=(dp<<TOT)|(dp<<(r-l+1-TOT));
        return 1;
    }
    signed main(){
    	for (rr int Test=iut();Test;--Test){
    		n=iut(),mx[0]=-1,mn[n+1]=0x3f3f3f3f,
    		flag=0,dp.reset(),dp[0]=las=1,ans=-1;
    		if (n==1) printf("-1
    ");
    		for (rr int i=1;i<=n;++i) a[i]=iut();
    		for (rr int i=1;i<=n;++i) mx[i]=mx[i-1]>a[i]?mx[i-1]:a[i];
    		for (rr int i=n;i>=1;--i) mn[i]=mn[i+1]<a[i]?mn[i+1]:a[i];
    		for (rr int i=1;i<=n;++i)
    		if (mx[i]<mn[i+1]){
    			if (!check(las,i)){
    				flag=1;
    				break;
    			}
    			las=i+1;
    		}
    		if (!flag){
    			for (rr int i=n/2;~i;--i)
    			if (dp[i]){
    				ans=n-i*2;
    				break;
    			}
    		}
    		printf("%d
    ",ans);
    	}
    	return 0;
    } 
    
  • 相关阅读:
    Cookie
    精英讲师培训笔记03-如何与台下观众有效互动
    精英讲师培训笔记02-培训师手势如何做
    精英讲师培训笔记01-提升口才的三个心法
    "怒海争锋"沙盘培训思考
    logback问题集
    spring boot2 启动过程
    Connect reset
    ELK 安装及使用
    常用中文教程网站
  • 原文地址:https://www.cnblogs.com/Spare-No-Effort/p/13523470.html
Copyright © 2020-2023  润新知