[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; }