• [BZOJ 1032][JSOI 2007]祖玛 题解(区间DP)


    [BZOJ 1032][JSOI 2007]祖玛

    Description

    https://www.lydsy.com/JudgeOnline/problem.php?id=1032

    Solution

    1.考虑初始化的方式。

    由于同色转移起来复杂,我们考虑把相邻的同色的球缩成一个球,记录下缩后的球代表的原来的个数。

    这时我们考虑对刷的表的初始化,f[L][R]表示[L,R]区间中需要打入的最小珠子数。

    由于是最小个数答案,所以全部初始化为正无穷,但对于缩后的状态,我们考虑不受其他合并时影响的结果:

    • 如果个数为1,那么此时需要打入两个同色球,f[i][i]=2;

    • 如果个数大于等于二,那么此时只需要打入一个同色球,f[i][i]=1;

    即:for(int i=1;i<=list[0];++i)f[i][i]=num[i]>1?1:2;

    2.考虑DP的方式:常见的枚举断点组合求解。

    但是我们注意此题的特殊性质:合并过程中两端球个数大于等于3直接消掉,所以如果两端颜色相等,我们枚举断点前先判断:

    • 如果两端球数合起来多于两个,那么直接等于左右向中间各缩进一个的答案;

    • 如果合起来等于两个,那么还需要再打入一个;

    即: if(list[l]==list[r]) f[l][r]=f[l+1][r-1]+(num[l]+num[r]>2?0:1);

    剩余部分直接枚举断点松弛大的区间即可。

    Code

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #define R register
    using namespace std;
    
    int num[510],list[510],f[510][510];
    
    inline int rd(){
    	int x=0;
    	bool f=1;
    	char c=getchar();
    	while(!isdigit(c)){
    		if(c=='-') f=0;
    		c=getchar();
    	}
    	while(isdigit(c)){
    		x=(x<<1)+(x<<3)+(c^48);
    		c=getchar();
    	}
    	return f?x:-x;
    }
    
    int init(int n){
    	int x,cnt=1;
    	for(int i=1;i<=n;++i)
    		for(int j=i;j<=n;++j)
    			f[i][j]=0x3f3f3f3f;
    	list[++list[0]]=rd();
    	for(int i=2;i<=n;++i){
    		x=rd();
    		if(x==list[list[0]])++cnt;
    		else{
    			num[list[0]]=cnt;
    			list[++list[0]]=x;
    			cnt=1;
    		}
    	}
    	num[list[0]]=cnt;
    	for(int i=1;i<=list[0];++i)f[i][i]=num[i]>1?1:2;
    }
    
    int main(){
    	init(rd());
    	for(int len=2;len<=list[0];++len)
    		for(int l=1;l<=list[0]-len+1;++l){
    			int r=l+len-1;
    			if(list[l]==list[r]) f[l][r]=f[l+1][r-1]+(num[l]+num[r]>2?0:1);
    			for(int k=l;k<r;++k) f[l][r]=min(f[l][r],f[l][k]+f[k+1][r]);
    		}
    	printf("%d",f[1][list[0]]);
    	return 0;
    }
    

    PS:对于三个离散的点聚集在一起的情况,标程是错误的,所以当年数据据说没有那种情况的,至今貌似还没有比较完美的解法,特判就好了......

    有关区间DP的其他讲解参考我的随笔:http://www.cnblogs.com/COLIN-LIGHTNING/p/9038198.html

  • 相关阅读:
    plsql调试存储过程卡住的原因以及处理
    JavaWeb三大组件(Servlet、Filter、Listener)的区别
    单点登录原理
    Oracle 导表异常处理方案 (解决空表导出出错问题)
    在Oracle中删除用户时提示:ORACLE无法删除当前连接用户
    VisualSvn的权限管理
    MySql常用命令总结
    Oracle 常用SQL
    参数
    java
  • 原文地址:https://www.cnblogs.com/COLIN-LIGHTNING/p/9038250.html
Copyright © 2020-2023  润新知