​VJ传送门​

感觉非常厉害…

先考虑白板刷到串 B B B的最小花费

首先 d p [ i ] [ j ] = d p [ i + 1 ] [ j ] + 1 dp[i][j]=dp[i+1][j]+1 dp[i][j]=dp[i+1][j]+1

这是单独刷 i i i位置

但是也可以在刷 k k k的时候顺便刷掉 i i i

此时当 b [ i ] = = b [ k ] b[i]==b[k] b[i]==b[k]

有转移 d p [ i ] [ j ] = d p [ i + 1 ] [ k ] + 1 + d p [ k + 1 ] [ j ] dp[i][j]=dp[i+1][k]+1+dp[k+1][j] dp[i][j]=dp[i+1][k]+1+dp[k+1][j]

至此,已经包含了所有的转移可能

那么现在不是白板,而是字符串 A A A,这可怎么办呢

令 a n s [ i ] ans[i] ans[i]为把 [ 1 , i ] [1,i] [1,i]刷的和 B B B一样的最小花费

当 a [ i ] = = b [ i ] a[i]==b[i] a[i]==b[i],显然 a n s [ i ] = a n s [ i − 1 ] ans[i]=ans[i-1] ans[i]=ans[i−1]

否则,去前面枚举一个 k k k

a n s [ i ] = a n s [ k ] + d p [ k + 1 ] [ j ] ans[i]=ans[k]+dp[k+1][j] ans[i]=ans[k]+dp[k+1][j]

#include <bits/stdc++.h>
using namespace std;
const int maxn = 109;
int n,m,dp[maxn][maxn],ans[maxn];
char a[maxn],b[maxn];
int main()
{
while( cin >> (a+1) >> (b+1) )
{
int len = strlen(a+1);
memset(dp,0,sizeof(dp));
for(int i=1;i<=len;i++) dp[i][i]=1;
for(int l=2;l<=len;l++)
for(int i=1;i+l-1<=len;i++)
{
int j = i+l-1;
dp[i][j] = min( dp[i+1][j],dp[i][j-1] )+( b[i]!=b[j] );
for(int k=i+1;k<=j;k++)
{
if( b[i]==b[k] )
dp[i][j] = min( dp[i][j], dp[i+1][k]+dp[k+1][j] );
}
}
for(int i=1;i<=len;i++)
{
ans[i] = dp[1][i];
if( a[i]==b[i] ) ans[i] = ans[i-1];
else
{
for(int j=1;j<i;j++)
ans[i] = min( ans[i],ans[j]+dp[j+1][i] );
}
}
cout << ans[len] << endl;
}
}