Description
GAL发现了N个特殊的字母序列,由小写字母组成。小L认为,对于两个字符串s1,s2,若s1是某个特殊序列的前缀,s2是该特殊序列的后缀,则称s1,s2被这个序列拥有。
现在小L给出M对s1,s2,对于每对字符串,问它们被几个特殊序列拥有。
Input
第1行一个整数N。
接下来N行,每行一个字符串,代表N个特殊序列。
第N+2行一个整数M。
接下来M行每行一对s1,s2用空格隔开。S1,s2是经过加密的。
设上一问的答案为lastans。解密方法是将s1,s2所有字母向后移动lastans个单位,这时你要把小写字母表当作一个环,比如z的下一个字母是a。
Output
对于每次询问操作,输出一个非负整数表示答案。
Sample Input
3
aaaaa
abacabaa
avtobus
6
a a
y yy
yy y
zzzzz zzzz
zazb bzaz
abac a
Sample Output
2
2
1
1
0
1
HINT
设N个特殊序列总长为L1,所有M组询问总长为L2。L1,L2<=2000000.N<=2000,M<=100000
解法: 自己只能写个自然溢出的hash,但是是ac不了的。看到了一位神牛留下的神奇做法,对于询问俩串长都小于20的,可知这种类型有解的情况只有2000*20*20种,把这些情况预处理答案用map存一下,然后直接查表,其余的暴力,我没有判,直接全部存了表。。。。然后发现也ac了。。
//BZOJ 3483
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long uLL;
const uLL mod = 1e9+7;
const int maxn = 2010;
int n, m, l[maxn];
string a[maxn];
char ch[2000010];
vector <uLL> L[maxn], R[maxn];
int ans;
void input()
{
scanf("%d", &n);
for(int i = 1; i <= n; i++){
scanf("%s", ch);
l[i] = strlen(ch);
for(int j = 0; j < l[i]; j++) a[i] += ch[j];
}
uLL last;
for(int i = 1; i <= n; i++){
last = 171;
for(int j = 0; j < l[i]; j++){
last = last*mod+a[i][j];
L[i].push_back(last);
}
}
for(int i = 1; i <= n; i++){
last = 171;
for(int j = 0; j < l[i]; j++){
last = last*mod+a[i][l[i]-j-1];
R[i].push_back(last);
}
}
}
void work()
{
scanf("%d", &m);
ans = 0;
while(m--)
{
uLL x = 171, y = 171;
scanf("%s", ch);
int len1 = strlen(ch);
for(int j = 0; j < len1; j++) ch[j] = (ch[j] - 'a' + ans)%26+'a';
for(int j = 0; j < len1; j++) x = x*mod + ch[j];
scanf("%s", ch);
int len2 = strlen(ch);
for(int j = 0; j < len2; j++) ch[j] = (ch[j] - 'a' + ans)%26 + 'a';
for(int j = 0; j < len2; j++) y = y*mod + ch[len2-j-1];
ans = 0;
for(int i = 1; i <= n; i++){
if(L[i][len1-1]==x && R[i][len2-1] == y) ans++;
}
printf("%d\n", ans);
}
}
void output()
{
//printf("%d\n", ans);
}
int main()
{
input();
work();
//output();
}