CF607B祖玛

题目描述

温温是一只懒惰的小萌猪。他虽然身负重任,但还是每天上班都偷偷玩游戏。今天,他决定玩一个叫做《祖玛》的老游戏。不过,温温打开游戏之后,发现这个游戏和印象里不太一样。
游戏开始时,温温会得到一串宝石,第i个宝石的颜色是ci。游戏的目标是摧毁所有宝石。在游戏的每一秒钟,温温可以选择宝石序列的任意一个回文子串(即连续的若干个宝石,从前往后和从后往前看颜色是一样的),把这些宝石摧毁。之后左右的宝石会向中间移动,重新组成一个连续的序列。
温温想知道他最少要花多长时间才能摧毁所有宝石。
题面翻译和魔改来自hl7.16模拟赛第一题

Input
第一行一个整数n,表示一共有n个宝石。
第二行n个整数ci,表示宝石的颜色。

时间限制:2s
数据范围:
1 ≤ ci ≤ n
1 ≤ n ≤ 20 for 30%
1 ≤ n ≤ 500 for 100%

Output
输出一个整数,表示最少所需时间。

Examples
input

3
1 2 1

output

1

input

3
1 2 3

output

3

input

7
1 4 4 2 3 2 1

output

2

在第三个样例中,温温可以先摧毁回文子串4 4,再摧毁回文子串1 2 3 2 1。

这道题刚看的时候第一反应就是要用马拉车写!(马拉车是求回文串的算法)
因为前几天刚学过(虽说不是一个老师吧)
然后就觉着自己凉了QAQ
于是自暴自弃写了个骗分代码(写了个玄学公式把三个样例过了)
(虽然三道题很毒瘤但是老师还是很贴心的把样例放进去了qwq)

这道题是一道dp题(记忆化搜索就过了)
因为数据范围很小,而且有2s的时间,回文串就直接朴素求(对与一段可能的区间,看两边是否相等)
然后我们看这道题,
对于一个区间[l,r];
区间最优解我们需要分类讨论:
①[l,r]是回文串,那么摧毁[l,r]我们只需要一步
②[l,r]不是回文串,那么[l,r]的摧毁状态就可以用两个小区间更新,那么我们就枚举[l,r]中的两个区间代价和的最小值;

然后我们就不断用小区间去更新大区间,每个区间都会遍历一次,用记忆化搜索或者dp写都行

#include

#define N 510
#define INF 0x3f3f3f3f

using namespace std;

int n, m;
int a[N], f[N][N];
int v[N][N];

int dp(int l, int r){	
	if(l == r) return 1;
	
	if(v[l][r]) return f[l][r];
	v[l][r] = 1;
	
	bool flg = 1;
	for(int i = l; i <= r; ++i){
		if(a[i] != a[r - i + l]){
			flg = 0; break;
		}
	}
	
	if(flg){
		f[l][r] = 1;
		return 1;	
	}
	
	int ans = INF;
	if(a[l] == a[r]){
		ans =  min(INF, dp(l + 1, r - 1));
	}
	
		for(int i = l; i < r; ++i){
		ans = min(ans, dp(l,i) + dp(i + 1, r));
	}
	
	f[l][r] = ans;
	return ans;
}

int main()
{
//	freopen("zuma.in", "r", stdin);
//	freopen("zuma.out", "w", stdout);
	memset(f, INF, sizeof(f));
	
	scanf("%d", &n);
	
	for(int i = 1; i <= n; ++i)
		scanf("%d", &a[i]);
	
	printf("%d\n", dp(1, n));	
	return 0;		
}

CF607B祖玛_第1张图片

你可能感兴趣的:(DP)