Codeforces 607B - Zuma (区间DP)

题意

给一串数字,每次可以消去任意一段连续的回文数字,问最少消去几次能消完。

思路

我们考虑最左端的点l。

要么l被单独消去, ans(l,r)=1+ans(l+1,r)
要么在 [l,r] 内存在一个 arr[k]=arr[l] ,这样的话这一对数字可以相当于「免费」消去一次。因为我们总是能把 [l+1,k1] 消去得只剩一个数字,这样和 l,k 组成一个回文串,代价由中间那个数承担。这时候 ans=dfs(l+1,k1)+dfs(k+1,r)
然而这样有一种特殊情况,就是 arr[l]=arr[l+1] ,这样的话没人帮他们承担代价,要特判一下。

PS:乍一看这题目我就想到了祖玛神殿。于是。。
我问旁边的队友:「玩过传奇没?」
队友思索了一番。
「没。」
才差一年,代沟不至于这么大吧(╯‵□′)╯ ┴─┴

代码

#include <stack>
#include <cstdio>
#include <list>
#include <cassert>
#include <set>
#include <iostream>
#include <string>
#include <vector>
#include <queue>
#include <functional>
#include <cstring>
#include <algorithm>
#include <cctype>
//#pragma comment(linker, "/STACK:102400000,102400000")
#include <string>
#include <map>
#include <cmath>
//using namespace std;
#define LL long long
#define ULL unsigned long long
#define SZ(x) (int)x.size()
#define Lowbit(x) ((x) & (-x))
#define MP(a, b) std::make_pair(a, b)
#define MS(p, num) memset(p, num, sizeof(p))
#define PB push_back
#define X first
#define Y second
#define ROP freopen("input.txt", "r", stdin);
#define MID(a, b) (a + ((b - a) >> 1))
#define LC rt << 1, l, mid
#define RC rt << 1|1, mid + 1, r
#define LRT rt << 1
#define RRT rt << 1|1
#define FOR(i, a, b) for (int i=(a); (i) < (b); (i)++)
#define FOOR(i, a, b) for (int i = (a); (i)<=(b); (i)++)
const double PI = acos(-1.0);
const int INF = 0x3f3f3f3f;
const double eps = 1e-8;
const int MAXN = 500 + 10;
const int MOD = 1e9 + 7;
const int dir[][2] = { {-1, 0}, {1, 0}, {0, -1}, {0, 1} };
const int seed = 131;
int cases = 0;
typedef std::pair<int, int> pii;

int dp[MAXN][MAXN];
int arr[MAXN];
int dfs(int l, int r)
{
    if (dp[l][r] != -1) return dp[l][r];
    if (l == r) return 1;
    if (l > r) return 0;
    int ret = 1 + dfs(l + 1, r);
    for (int i = l + 2; i <= r; i++) if (arr[l] == arr[i])
        ret = std::min(ret, dfs(l + 1, i - 1) + dfs(i + 1, r));
    if (arr[l] == arr[l + 1]) ret = std::min(ret, 1 + dfs(l + 2, r));
    return dp[l][r] = ret;
}

int main()
{
    //ROP;
    int n;
    scanf("%d", &n);
    MS(dp, -1);
    for (int i = 1; i < n + 1; i++) scanf("%d", &arr[i]);
    printf("%d\n", dfs(1, n));
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值