• LOJ#3271. 「JOISC 2020 Day1」建筑装饰 4 DP+找规律


    有一个非常显然的 DP:   

    $f_{i,j,0/1}$ 表示当前 $DP$ 到 $i$,选了 $j$ 个 A,当前位置选的是 A/B 是否可行.  

    状态数为 $O(n^2)$,转移为 $O(1)$,时间复杂度为 $O(n^2)$.   

    这个时候就要动用人类智慧:打表.   

    打表后发现当 $i,0/1$ 固定的时候 $j$ 的合法状态是一个连续段.  

    所以对于 $f_{i,0/1}$ 只需维护做右端点即可,转移的话取一个区间并集.  

    输出方案倒着做就行了.  

    code: 

    #include <cstdio> 
    #include <cstring> 
    #include <algorithm> 
    #define N 500009     
    #define ll long long 
    #define inf 1000000002 
    #define setIO(s) freopen(s".in","r",stdin)  
    using namespace std;   
    int n;   
    char ans[N<<1];  
    struct data { 
    	int l,r;   
    	data(int l=0,int r=0):l(l),r(r){}  
    }f[N<<1][2];   
    int a[N<<1],b[N<<1];   
    void upd(data &a,data b) { 
    	a.l=min(a.l,b.l);  
    	a.r=max(a.r,b.r);          
    }
    int main() { 
    	// setIO("input");   
    	scanf("%d",&n);   	
    	int x,y,z,m=n<<1;  
    	f[0][1]=data(0,0);
    	for(int i=1;i<=m;++i) {
    		scanf("%d",&a[i]); 
    	}  
    	for(int i=1;i<=m;++i) { 
    		scanf("%d",&b[i]);  
    	}   	
    	for(int i=1;i<=m;++i) { 
    		f[i][0]=f[i][1]=data(inf,-inf);   
    		if(a[i-1]<=a[i]) upd(f[i][0],f[i-1][0]);  
    		if(b[i-1]<=a[i]) upd(f[i][0],f[i-1][1]);  
    		if(a[i-1]<=b[i]) upd(f[i][1],f[i-1][0]);  
    		if(b[i-1]<=b[i]) upd(f[i][1],f[i-1][1]);  
    		++f[i][0].l,++f[i][0].r;   
    	}        
    	if(n<min(f[m][0].l,f[m][1].l)||n>max(f[m][0].r,f[m][1].r)) { 
    		printf("-1
    ");
    	} 
    	else {  
    		int fl=(n>=f[m][0].l&&n<=f[m][0].r)?0:1;  
    		for(int i=m;i>=1;--i) {   
    			int v=fl?b[i]:a[i];       
    			ans[i]=fl?'B':'A';    
    			n-=(!fl);                    
    			if(v>=a[i-1]&&(n>=f[i-1][0].l&&n<=f[i-1][0].r)) fl=0;  
    			else fl=1;   
    		}
    		for(int i=1;i<=m;++i) { 
    			printf("%c",ans[i]);    
    		}
    	}
    	return 0; 
    } 
    

      

  • 相关阅读:
    周鸿祎:很多程序员聪明,但我一看就知道他不会成功
    Ubuntu/centos/redhat/SUSE sipp安装(带rtp支持,3.5.1版本)
    ffmpeg源码分析之媒体打开过程
    搜集的动植物分类、检索网站
    sipp命令 各参数含义
    最简单的一个win32程序
    vi学习笔记
    删除结点 (双向链表)
    插入结点(双向链表)
    La=LaULb (单链表)
  • 原文地址:https://www.cnblogs.com/guangheli/p/13425181.html
Copyright © 2020-2023  润新知