*点击

[IOI2000] 回文字串

题目

Description

回文词是一种对称的字符串。任意给定一个字符串,通过插入若干字符,都可以变成回文词。此题的任务是,求出将给定字符串变成回文词所需要插入的最少字符数。

比如 “Ab3bd”插入2个字符后可以变成回文词“dAb3bAd”或“Adb3bdA”,但是插入少于2个的字符无法变成回文词。

注:此问题区分大小写

Input

一个字符串(0<strlen<=1000).

Output

有且只有一个整数,即最少插入字符数

Sample Input

Ab3bd

Sample Output

2

思路

这是一道类似区间$dp$的题目;

我们可以设 $dp[i][j]$ 表示在 $i$ 到 $j$ 区间内,合成回文串需要加多少字母;

那么很明显我们要考虑两种情况:

$if~(i==j)$ 

    $dp[i][j]=dp[i+1][j-1]$

如果 $i$ , $j$  相等,那么两头相等,就不需要多插入什么;

例如 $dp[abcfa]=a[bcf]$ ;

 

$else$

    $dp[i][j]=min(dp[i+1][j],dp[i][j-1])+1$

否则, 说明串的两头不同,需要多插入$1$字符以保持回文性质,新插入的字符可能在右边,可能在左边;

例如 $dp[abcdf]=min(dp[abcd],dp[bcdf])+1$ ;

 

代码

#include<bits/stdc++.h>
#define re register
typedef long long ll;
using namespace std;
inline ll read()
{
    ll a=0,f=1; char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}
    while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}
    return a*f;
}
ll n;
char s[1010];
ll dp[1010][1010];
int main()
{
    scanf("%s",s+1);//输入 
    n=strlen(s+1);
    for(re ll len=2;len<=n;len++)//枚举区间长度 
    for(re ll i=1;i<=n-len+1;i++) 
    {
        ll j=i+len-1;
        if(s[i]==s[j])//如果 i j 相等 
            dp[i][j]=dp[i+1][j-1];
        //那么两头相等,就不需要多插入什么
        else
            dp[i][j]=min(dp[i+1][j],dp[i][j-1])+1;
        //说明串的两头不同,需要多插入 1 字符以保持回文性质
    }
    printf("%lld\n",dp[1][n]);//没了 
    return 0;
}

 

posted @ 2020-09-30 20:27  木偶人-怪咖  阅读(154)  评论(0编辑  收藏  举报
*访客位置3D地图 *目录