tommy 第一次在这个网站上发 (逃
题意
将一个串变成完美串的最小编辑代价,其中将字符 编辑为字符
的代价为
,完美串的定义为任意长度
的子串都不为回文串。
解法
做过 这题的可能会立刻发现,任何一个回文串都是有对称中心的,对称中心对应了两种基本串:长度为
和长度为
的回文串。只要整个字符串中不存在这两种串,那么这个字符串中就不存在任意长度
的回文串。
于是想到 ,定义状态为
表示前
个字符,第
个字符为
,第
个字符为
的最小编辑代价。但是状态数是
的,其中
为字符集大小。
观察一下,发现如果修改一个字符,其代价一定不会超过 。因为代价不超过
的有
个字符,在能修改的情况下我们肯定尽可能希望代价最小。 不妨优化状态定义,设
为前
个字符,修改后第
个字符与
的距离为
,第
个字符与
的距离为
。通过修改状态定义,状态数缩减至
。
滚动数组后总空间复杂度可优化至 。
代码
#include<cstdio>
#include<cstring>
#define register
char s[1000005];
int f[5][5],tmp[5][5];
inline int abs(const int &x) {
return x<0? -x:x;
}
inline int min(const int &x,const int &y) {return x<y? x:y;}
int main() {
int n;
scanf("%d%s",&n,s+1);
for(register int j=0;j<5;++j) {
for(register int k=0;k<5;++k) {
f[j][k]=0x3f3f3f3f;
}
}
for(register int i=-2;i<=2;++i) {
f[i+2][0]=abs(i);
}
for(register int i=1;i<n;++i) {
for(register int j=0;j<5;++j) {
for(register int k=0;k<5;++k) {
tmp[j][k]=0x3f3f3f3f;
}
}
for(register int j=-2;j<=2;++j) {
for(register int k=-2;k<=2;++k) {
for(register int l=-2;l<=2;++l) {
if((j+s[i+1]+26)%26==(k+s[i]+26)%26) continue;
if(i>1&&((j+s[i+1]+26)%26==(l+s[i-1]+26)%26)) continue;
tmp[j+2][k+2]=min(tmp[j+2][k+2],f[k+2][l+2]+abs(j));
}
}
}
for(register int j=0;j<5;++j) {
for(register int k=0;k<5;++k) {
f[j][k]=tmp[j][k];
}
}
}
int ans=0x3f3f3f3f;
for(register int i=0;i<5;++i) {
for(register int j=0;j<5;++j) {
ans=min(ans,f[i][j]);
}
}
printf("%d\n",ans);
return 0;
} 
京公网安备 11010502036488号