CodeForces - 607B Zuma

Posted on 2021-12-29 14:27  Capterlliar  阅读(13)  评论(0编辑  收藏  举报

题意:给出一串数字,每次删一个回文子数组,剩下的拼起来接着删,求最少几次能删完。

解:第一想法是找出所有回文子数组,如果大区间是回文直接等于1。写写发现没必要,直接转就完了。

首先设dp[i][j]为区间[i,j]最少几步删完。然后套路地拿小区间去拼,没有特殊情况大区间等于两个小区间之和。

特殊情况是,删掉一个子区间后,剩下的是个回文,可以一步删完,或者一整个是个回文。这时候首先a[i]==a[j]。如果删掉一个子区间剩下的是回文,那说明另一个子区间也是回文,整体删掉步数等于dp[i+1][j-1];整体是一个回文也一样。

2还是要特判一下。回文好烦,一不小心就漏情况了。

代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define maxx 505
#define eps 0.00000001
#define inf 0x3f3f3f3f
#define mod 1000000007
//#define int long long
int dp[maxx][maxx]={0};
int a[maxx];
int n;
signed main() {
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    for(int i=1;i<=n;i++)
        dp[i][i]=1;
    for(int len=2;len<=n;len++){
        for(int i=1;i<=n-len+1;i++){
            int j=i+len-1;
            if(len==2&&a[i]==a[j])
                dp[i][j]=1;
            else if(len>2&&a[i]==a[j])
                dp[i][j]=dp[i+1][j-1];
            else
                dp[i][j]=inf;
            for(int k=i;k<=j;k++)
                dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]);
        }
    }
    printf("%d\n",dp[1][n]);
    return 0;
}
View Code