思维比较好想的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了