思维比较好想的hash,但是要双哈希
于是要用map<pair<long long,long long>,int>
AC代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<map>
#include<cstring>
using namespace std;
const int MAXN = 4e5+77;
string ss[MAXN],s[MAXN];
map<pair<long long ,long long>,int>cs;
map<string,int>cnt;
const long long BASE[2] = {12345,1234567};
const long long MOD[2] = {1000000007,1000000009};
long long inv_BASE[2];
long long mc[2][MAXN];
long long qpow(long long a,long long b,long long c){
long long res = 1;
for(;b;b>>=1,a = a * a % c){
if(b&1) res = res * a % c;
}
return res;
}
void pre(int n){
mc[0][0] = mc[1][0] = 1;
for(int i = 1;i <= n;i++) {
mc[0][i] = mc[0][i-1] * BASE[0] % MOD[0];
mc[1][i] = mc[1][i-1] * BASE[1] % MOD[1];
}
inv_BASE[0] = qpow(BASE[0],MOD[0] - 2,MOD[0]);
inv_BASE[1] = qpow(BASE[1],MOD[1] - 2,MOD[1]);
}
pair<long long,long long>pp;
void insert(string s){
long long res[2] = {0,0};
for(int e = 0;e < 2;e++){
for(int i = 0;s[i];i++){
res[e] = (res[e] * BASE[e] + s[i]) % MOD[e];
}
}
//cout<<"res0 " << res[0] << " res1 " << res[1] <<"\n";
pp.first = res[0];pp.second = res[1];
cs[pp]++;
cnt[s]++;
}
int n;
long long ans = 0;
void cal(string s){
long long hs1[2] = {0,0},hs2[2] = {0,0},hs3[2];
long long res[2] = {0,0};
for(int e = 0;e < 2;e++){
for(int i = 0;s[i];i++){
res[e] = (res[e] * BASE[e] + s[i]) % MOD[e];
}
hs3[e] = res[e];
}
long long ct = cnt[s];
for(int i = 0, j = s.length() - 1;j - i > 1;i++,j--){
for(int e = 0;e < 2;e++){
hs1[e] = (hs1[e] * BASE[e] + s[i]) % MOD[e];
hs2[e] = (hs2[e] + mc[e][i] * s[j]) % MOD[e];
hs3[e] = (hs3[e] - mc[e][j-i] * s[i] - s[j]) % MOD[e] * inv_BASE[e] % MOD[e];
hs3[e] = (hs3[e] + MOD[e]) % MOD[e];
}
if(hs1[0] == hs2[0] && hs1[1] == hs2[1]){
pp.first = hs3[0],pp.second = hs3[1];
ans += 1ll * ct * cs[pp];//cs[pp]是map<pair<long long,long long>,int>
//ans += 1ll * cnt[s] * cs[pp];
}
}
}
int main()
{
pre(4e5+7);
cin>>n;
for(int i = 1;i <= n;i++){
cin>>s[i];
insert(s[i]);
}
for(int i = 1;i <= n;i++){
long long ct = cnt[s[i]];
if(ct){
ans += 1ll * ct * (ct-1) / 2;
cal(s[i]);
cnt[s[i]] = 0;
}
}
cout<<ans<<"\n";
return 0;
}
但是这样是TLE的:
void cal(string s){
long long hs1[2] = {0,0},hs2[2] = {0,0},hs3[2];
long long res[2] = {0,0};
for(int e = 0;e < 2;e++){
for(int i = 0;s[i];i++){
res[e] = (res[e] * BASE[e] + s[i]) % MOD[e];
}
hs3[e] = res[e];
}
//long long ct = cnt[s];
for(int i = 0, j = s.length() - 1;j - i > 1;i++,j--){
for(int e = 0;e < 2;e++){
hs1[e] = (hs1[e] * BASE[e] + s[i]) % MOD[e];
hs2[e] = (hs2[e] + mc[e][i] * s[j]) % MOD[e];
hs3[e] = (hs3[e] - mc[e][j-i] * s[i] - s[j]) % MOD[e] * inv_BASE[e] % MOD[e];
hs3[e] = (hs3[e] + MOD[e]) % MOD[e];
}
if(hs1[0] == hs2[0] && hs1[1] == hs2[1]){
pp.first = hs3[0],pp.second = hs3[1];
//ans += 1ll * ct * cs[pp];//cs[pp]是map<pair<long long,long long>,int>
ans += 1ll * cnt[s] * cs[pp];
}
}
}
差别就在于cnt[s]是只访问一次和访问多次,为什么就TLE了