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