Codeforces-336-div2-D-Zuma

img

题目链接:

Go!

题目大意:

​ 给你一个长度为 n 的序列 c,每次操作删去当前序列的一个回文串。问:把序列全部删完,最少需要多少次的操作?

数据范围:

1n105

1cin

样例:

input

3
1 2 1

output

1

In the first sample , Genos can destroy the entire line in one second.

input

3
1 2 3

output

3

In the second sample , Genos can only destroy one gemstone at a time, so destroying three gemstones takes three seconds.

input

7
1 4 4 2 3 2 1

output

2

In the third sample , to achieve the optimal time of two seconds , destroy palindrome 4 4 first and then destroy palindrome 1 2 3 2 1 .

解题思路:

这是一道 区间 dp

  • 状态方程 dp[i][j] 代表完全删除区间 (i,j) 最少需要多少次操作?

  • 转移方程

    • 区间 (i,j) 可以由 区间 (i,k) + 区间 (k+1,j) 转移而来。
    • c[i] = c[j] 时,区间 (i,j) 也可以由 区间 (i+1,j1) 转移而来。(需要注意的是:当 i+1=j 时,直接 dp[i][j] = 1,否则会出现 i+1>j1 的情况)
  • 小思考1:为什么最外层是枚举 区间长度,而不是直接枚举 区间端点 l,r 呢?

    • 答:因为我们转移的时候是从 小区间 转移到 大区间 的。
  • 小思考2: 当 c[i]=c[j] 时,为什么 区间 (i,j) 是直接由 区间 (i+1,j1) 转移而来,而不是由 区间 (i+1,j1) + 1 转移而来?

    • 答:因为,若完全删除 区间 (i+1,j1) 最少需要 k 次操作,那么我们可以在前 k1 次操作删掉 区间 (i+1,j1) k1 部分,剩下的一部分可以与 c[i],c[j] 形成一个回文串,最后再一起删掉,所以总操作次数还是 k 次。
  • 最后答案dp[1][n]

AC代码:

#include<bits/stdc++.h>
using namespace std;

const int inf = 1 << 30;
int c[505],dp[505][505];// dp[i][j] : 完全删除区间 (i,j) 最少需要多少次操作?

int main(){
    int n;cin >> n;
    memset(dp,0x3f,sizeof(dp));// 初始化为正无穷。
    for(int i = 1;i <= n;i++) cin >> c[i], dp[i][i] = 1;// 删除一个数时需要一次操作。
    for(int len = 2;len <= n;len++){// 枚举区间长度。
        for(int l = 1;l <= n - len + 1;l++){//枚举左端点。
            int r = l + len - 1;//右端点。
            for(int k = l;k < r;k++){
                dp[l][r] = min(dp[l][r],dp[l][k] + dp[k + 1][r]);
                  // 代表区间(l,r) 可以由 (l,k) + (k + 1,r) 转移。
            }
            if(c[l] == c[r]){//当 a[l] = a[r]时。
                if(l + 1 == r) dp[l][r] = 1;//若相邻,则需要一次操作。
                dp[l][r] = min(dp[l][r],dp[l + 1][r - 1]);// (l,r) 当然可以由 (l + 1,r - 1) 转移。
            }
        }
    }
    cout << dp[1][n] << endl;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值