51Nod 1154 回文串划分

Problem

有一个字符串S,求S最少可以被划分为多少个回文串。
例如:abbaabaa,有多种划分方式。

a|bb|aabaa - 3 个回文串
a|bb|a|aba|a - 5 个回文串
a|b|b|a|a|b|a|a - 8 个回文串

其中第1种划分方式的划分数量最少。

Solution

先预处理,然后见官方攻略:

𝑑𝑝[𝑖]表示以𝑖结尾的划分数量的最小值,𝑑𝑝[𝑖]=𝑚𝑖𝑛(𝑑𝑝[𝑖],𝑑𝑝[𝑗]+1) 当𝑗<𝑖且从𝑗到𝑖是一个回文串时。所以对于字符𝑆,逐个处理𝑆的字符,枚举以𝑆𝑖为中心的所有回文串,做状态转移即可。复杂度𝑂(𝑛2)。

Code

#include<stdio.h>
#include<set>
#include<iostream>
#include<stack>
#include<cstring>
#include<cmath>
#include<vector>
#include<map>
#include<queue>
#include<algorithm>
typedef long long ll;
typedef long double ld;
typedef double db;
#define io_opt ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
const int mod=1e9+7;
inline int mo(ll a,int p){
    return a>=p?a%p:a;
}
inline int rd() {
    int x = 0, f = 1;
    char ch;
    while (ch < '0' || ch > '9') {
        if (ch == '-')f = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9') {
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    return f * x;
}
inline ll gcd(ll x, ll y){
    return y==0?x:gcd(y,x%y);
}
inline ll speed(ll a,ll b,int p){
    ll cur=a,anss=1;
    while(b){
        if(b&1) anss=anss*cur%p;
        cur=cur*cur%p;
        b>>=1;
    }
    return anss%p;
}
const int MAXN=1e5;
bool ipr[MAXN+20];
/*int cnt,pri[MAXN/5];
void prime(){//埃式筛法
    int N=sqrt(MAXN)+0.5,mul;
    memset(ipr,true,sizeof(ipr));
    ipr[1]=false;
    for(int i=2;i<=N;i++){
        if(ipr[i]==true){
            i==2?mul=1:mul=2;
            for(int j=i*i;j<=MAXN;j+=i*mul){
                ipr[j]=false;
            }
        }
    }
    for(int i=2;i<=MAXN;i++){
        if(ipr[i]==true){
            pri[++cnt]=i;
        }
    }
}*/
int len;
char s[5020];
int dp[5020][5020];
int dp2[5020];
vector<int>vec;
int main(){
    //io_opt;
    scanf("%s",s);
    len=strlen(s);
    for(int i=len-1;i>=0;i--){
        dp[i][i]=1;
        for(int j=i+1;j<len;j++){
            if(s[i]==s[j]){
                if(i+1>=j-1) dp[i][j]=1;
                else dp[i][j]=dp[i+1][j-1];
            }
        }
    }
    for(int i=0;i<len;i++){
        dp2[i]=dp[0][i]?1:i+1;
        if(dp2[i]>1) for(int j=0;j<i;j++){
            if(dp[j+1][i]&&dp2[j]+1<dp2[i]) dp2[i]=dp2[j]+1;
        }
    }
    printf("%d\n",dp2[len-1]);
    return 0;
}


posted @ 2020-06-27 09:59  CCWUCMCTS  阅读(147)  评论(0编辑  收藏  举报