周三做这场比赛的练习,这题过的人挺多的,但是一直没有好的思路。当时想的时候以为是字典树,但是具体的不知道该怎么做,后来看别人AC的代码才知道用简单的字符串哈希,或者其他的比如字母个数的限制条件优化一下就能过了,确实挺简单的,当时没有想到。写这题也没找什么字符串哈希的函数就是简单的哈希一下,如果相同再枚举判断一下就好了,有人可能对自己的哈希函数(或者说是人品)太自信,哈希值一样就认为是回文,我那样的策略不再判断是会WA的,判断后也不太慢632ms
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
char str[1005][505];
char antistr[1005][505];
long long hash[2][1005];
int len[1005];
long long po[505];
long long change(char* str,int len)
{
long long temp=0;
for(int i=0;i<len;i++)
{
temp=26*temp+str[i]-'a';
}
return temp;
}
bool judge(int x,int y)
{
long long s1=hash[0][x]*po[len[y]]+hash[0][y],s2=hash[1][y]*po[len[x]]+hash[1][x];
if(s1!=s2)
return false;
else
{
string temp="";
temp+=str[x];
temp+=str[y];
int len=temp.size();
for(int i=0;i<len/2;i++)
{
if(temp[i]!=temp[len-i-1])
return false;
}
}
return true;
}
int main()
{
//freopen("input.txt","r",stdin);
po[0]=1;
for(int i=1;i<=500;i++)
po[i]=po[i-1]*26;
int t;
scanf("%d",&t);
for(int cas=1;cas<=t;cas++)
{
printf("Case #%d: ",cas);
int n;
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%s",str[i]);
len[i]=strlen(str[i]);
hash[0][i]=change(str[i],len[i]);
for(int j=0;j<len[i];j++)
antistr[i][j]=str[i][len[i]-j-1];
hash[1][i]=change(antistr[i],len[i]);
}
int ans=0;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
{
if(i==j)
continue;
if(judge(i,j))
ans++;
}
printf("%d\n",ans);
}
}