BZOJ 1710. [Usaco2007 Open]Cheappal 廉价回文

传送门

看一眼感觉不太可做,推推性质

发现因为回文串去掉左右还是回文的,所以为了构成回文添加一个字符其实等价于删除另一边对应的字符

那么删除字符的代价就直接和添加字符的代价取最小值

然后考虑 $dp$,设 $f[l][r]$ 表示当前 $[l,r]$ 的区间内删除若干字符后成为回文串的最小代价,因为回文去掉两边还是回文

所以如果 $l,r$ 处的字符相等那么可以从 $f[l+1][r-1]$ 转移

当然对于任何位置都有转移: $f[l][r]=f[l][r-1]+cost[s[r]],f[l][r]=f[l+1][r]+cost[s[l]]$,其中 $cost[s[i]]$ 表示把位置 $i$ 的字符删除的代价

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
inline int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
    return x*f;
}
const int N=2007;
int n,m,cst[233],f[N][N];
char s[N];
int main()
{
    n=read(),m=read();
    scanf("%s",s+1); char ch[7]; int a,b;
    for(int i=1;i<=n;i++)
    {
        scanf("%s",ch),a=read(),b=read();
        cst[ch[0]-'a']=min(a,b);
    }
    memset(f,0x3f,sizeof(f));
    for(int i=1;i<=m;i++)
        for(int j=i+1;j<=m;j++) f[j][i]=0;
    for(int i=m;i;i--)
        for(int j=i;j<=m;j++)
        {
            if(i==j) { f[i][j]=0; continue; }
            f[i][j]=min(f[i][j-1]+cst[s[j]-'a'],f[i+1][j]+cst[s[i]-'a']);
            if(s[i]==s[j]) f[i][j]=min(f[i][j],f[i+1][j-1]);
        }
    printf("%d\n",f[1][m]);
    return 0;
}
View Code

 

posted @ 2019-08-27 11:34  LLTYYC  阅读(217)  评论(0编辑  收藏  举报