P1435 [IOI2000] 回文字串 / [蓝桥杯 2016 省] 密码脱落题解
作者:互联网
【题目链接】
【解题思路】
这题我们要将一个长度为
n
n
n 的字符串改成一个回文字符串,最坏情况下我们也只需要插入
n
n
n 个字符,但是很显然有些字符是不需要我们插入的,那么我们就可以考虑去重。
怎么去重呢?
我们可以吧这个字符串反过来,和原字符串形成一个对照,求一个最长公共子序列(也就是相同的部分),用字符串的长度减去最长公共子序列的长度(也就是不同的部分),即为问题所求。
证明:
Ab3bd
反过来为
db3bA
这样子我们就发现其实
b
3
b
b3b
b3b 是重复的,我们只要将
d
d
d 和
A
A
A 复制上去就行了。
也就是将第二个字符串与第一个字符串不同的字符复制上去即可。
【CODE】
#include<iostream>
#include<algorithm>
using namespace std;
int n,len1;
string s,str1,str2;
short d[5010][5010];
int main()
{
cin>>s;
str1=s;
reverse(s.begin(),s.end());//STL中的函数将字符串翻转
str2=s;
len1=s.size();
//最长公共子序列
for (int i=1;i<=len1;i++)
for (int j=1;j<=len1;j++)
if (str1[i-1]==str2[j-1])
d[i][j]=d[i-1][j-1]+1;
else d[i][j]=max(d[i-1][j],d[i][j-1]);
cout<<len1-d[len1][len1];
return 0;
}
【思路二】
与第一个的思路差不多,我们还可以将这个字符串中间分段,再将后一段反过来求最长公共子序列就可以了。
Tips:
如果长度是奇数中间的字符可以不管,我们在一个长度为偶数的回文字符串的最中间插入一个字符他还是一个回文字符串。
如果长度是偶数的话,直接平均分成两半就行了。
Ab3bd
变成
Ab db
再求一个最长公共子序列,
则
结
果
=
(
分
段
后
的
字
符
串
长
度
减
去
−
公
共
子
序
列
的
)
×
2
结果=(分段后的字符串长度减去-公共子序列的) \times2
结果=(分段后的字符串长度减去−公共子序列的)×2
证明:
如果这个字符没有算进最长公共子序列,那么它肯定就与后面的不同,我们只要将后面与前面不同的部分复制到前面,前面与后面不同的部分复制到后面,这样原字符串就被我们改成了回文字符串。
那么为什么,第二种做法需要在后面乘上一个 2 2 2,而第一种做法却不用呢?
因为我们第一种做法是将原字符串倒着复制了一份,而后来产生的字符串其实是不存在的,所以我们只要将下面的字符串复制到上面就可以了。
但是第二种的话我们是将原字符串分为两个字符串,这两个字符串都是原字符串的一部分,所以我们两个都需要改动,操作次数就要乘上一个
2
2
2。
代码就不放出来了,有兴趣的可以自己打一下。
标签:IOI2000,题解,最长,蓝桥,序列,公共,字符串,长度,我们 来源: https://blog.csdn.net/m0_57275564/article/details/121795491