题目链接:https://nanti.jisuanke.com/t/41415
题解:对于两边的,要哈希出相应的权重,中间的字符顺序无所谓,只关心是什么字符,所以哈希出每个字符的权重即可。
官方题解:
• 但是因为询问有20000个,O(NM)肯定超时的。
• 所以对于长度一样的询问可以弄在一起搞,因为窗口大小是一样 的。
• 所有询问的总长不超过100000,不同长度的个数最多也是
sqrt(100000)级别的(最坏情况是长度为2+3+4+…)。
• 解法就是:
• 1) 把M个询问的字符串的Hash值丢入一个unordered_map
• 2) 按照询问的不同长度,对母串循环sqrt(100000)次,滑动窗口
求出Hash值,累加到unordered_map中。
• 3) 输出答案即可。
我用unordered_map一直超内存,我看时间很充裕,就把对于每个长度跑完记录一下,接着计算出此时对于查询的贡献,6280ms
#include <bits/stdc++.h>
#include <tr1/unordered_map>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N = 1e5 + 10;
const ll ha = 1e9 + 7;
ull mp[N];
int tot;
int m;
char s[N], t[N];
ull q[N];
int vis[N];
ull has[33];
int ans[N];
int main() {
has[0] = 1;
for(int i = 1; i < 33; i++)
has[i] = has[i - 1] * ha;
int T;
int len, cntlen;
ull tmp;
scanf("%d", &T);
while(T--) {
memset(vis, 0, sizeof(vis));
tot = 0;
scanf("%s", s + 1);
len = strlen(s + 1);
scanf("%d", &m);
for(int i = 1; i <= m; i++) {
scanf("%s", t);
cntlen = strlen(t);
tmp = 0;
vis[cntlen] = 1;
for(int j = 1; j < cntlen - 1; j++)
tmp += has[t[j] - 'a'];
tmp += has[27] * t[0] + has[28] * t[cntlen - 1];
q[i] = tmp;
ans[i] = 0;
}
for(int i = 2; i <= 100000; i++) {
if(!vis[i]) continue;
tmp = 0;
tot = 0;
for(int j = 1; j <= len - i + 1; j++) {
if(j == 1) {
tmp = has[27] * s[1] + has[28] * s[i];
for(int k = 2; k < i; k++)
tmp += has[s[k] - 'a'];
} else {
tmp -= has[27] * s[j - 1] + has[28] * s[j - 1 + i - 1];
tmp += has[27] * s[j] + has[28] * s[j + i - 1];
if(i > 2) {
tmp -= has[s[j] - 'a'];
tmp += has[s[j + i - 2] - 'a'];
}
}
mp[tot++] = tmp;
}
sort(mp, mp + tot);
for(int j = 1; j <= m; j++)
ans[j] +=upper_bound(mp, mp + tot, q[j]) - lower_bound(mp, mp + tot, q[j]);
}
for(int i = 1; i <= m; i++) {
printf("%d\n", ans[i]);
}
}
return 0;
}