一道双哈希题,但是为什么TLE??2021山东icpc省赛 F题 Birthday Cake

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

posted @ 2021-11-07 18:56  beta_dust  阅读(58)  评论(0编辑  收藏  举报