题目链接:http://acm.dlut.edu.cn/problem.php?id=1250
题目描述:
给你一个字符串,问至少往这个串的最右端加几个字符能使它变成一个回文串?(每次都只能在字符串的最右端添加字符)
解题思路:
任意一个字符串的最右端肯定有一个回文串(哪怕这个回文串只有一个字符那么长),这道题的目的就是找出最右端这个回文字串有多长,总长度减去这个回文字串的长度就是答案。
想法不怎么难,字符串倒过来哈希就行了,但是第一会写哈希,WA了好几发。错误代码的问题出在,计算哈希值的时候,一旦这个哈希值已经爆ll被取模了,那么这个数字就不再具有数学意义,它只能存储代表字符串的信息而已,去运算它毫无意义,必然不对,后来改成用一个数组来存储好我想用的哈希值,然后比较的办法,就没问题了。下面给出错误的代码,和正确的做法。
错误代码:
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
typedef unsigned long long ll;
const int base = 10;
const int maxn = 1100000;
char str[maxn],rev[maxn];
ll xp[maxn];
ll hash[maxn];
int main()
{
freopen("input.txt","r",stdin);
int T,i,j;
scanf("%d",&T);
xp[0]=1;
for(i=1;i<maxn;i++)
xp[i]=xp[i-1]*base;
while(T--)
{
memset(rev,0,sizeof(rev));
memset(str,0,sizeof(str));
scanf("%s",str);
int len=strlen(str);
for(i=0,j=len-1;i<len;i++,j--)
{
rev[i]=str[j];
}
ll str_num=0;
ll rev_num=0;
for(i=len-1;i>=0;i--)
{
str_num=str_num*base+str[i]-'a'+1;
rev_num=rev_num*base+rev[i]-'a'+1;
}
int ans=len;
while(ans>=1)
{
if(rev_num==str_num)
break;
str_num=(str_num-str_num%base)/base; //超出long long被取模后,这种运算毫无意义!必然出错!
rev_num=rev_num%xp[ans-1];
ans--;
}
printf("%d\n",len-ans);
}
return 0;
}
AC代码:
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
typedef unsigned long long ll;
const int base = 31;
const int maxn = 1100000;
char str[maxn];
ll str_hash[maxn],rev_hash[maxn],xp[maxn];
int main()
{
freopen("input.txt","r",stdin);
int T,i,j;
scanf("%d",&T);
xp[0]=1;
for(i=1;i<maxn;i++)
xp[i]=xp[i-1]*base;
while(T--)
{
memset(str,0,sizeof(str));
memset(rev_hash,0,sizeof(rev_hash));
memset(str_hash,0,sizeof(str_hash));
scanf("%s",str);
int len=strlen(str);
str_hash[len-1]=rev_hash[len-1]=str[len-1]-'a'+1;
for(i=len-2;i>=0;i--)
{
str_hash[i]=(str[i]-'a'+1)*xp[len-i-1]+str_hash[i+1];
rev_hash[i]=rev_hash[i+1]*base+str[i]-'a'+1;
}
for(i=0;i<len;i++)
{
if(str_hash[i]==rev_hash[i])break; //比较之前存好的值,必然没问题!
}
cout<<i<<endl;
}
return 0;
}
AC截图: