bzoj没有题面,题面在vijos。
所以说读入char再丢给string并不会慢…
短串扔到hash表里。
长串的前半部分复制一份,然后在上面跑,若长串的后半部分出现过,则答案加上后面的hash值的出现次数。
写了双hash+挂链表,因为写了指针,并且双hash常数大,所以TLE+MLE,还有莫名其妙的WA…………
自然溢出+map在vijos上就是过不了……T两个点,不过在bzoj还是能A的。
看题解有人写的在bool数组中若已被占用则往后跳…在bzoj实测表现和map差不多…vijos也是T两个点…
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<map>
using namespace std;
typedef unsigned long long ULL;
typedef long long LL;
const int SZ = 4000010;
const int base = 13331;
string S1[SZ],S2[SZ];
map<ULL,int> h;
ULL hash[SZ],mi[SZ];
ULL gethash(string s)
{
ULL ans = 0;
for(int i = 0;i < s.length();i ++)
ans = ans * base + s[i] - 'a' + 1;
return ans;
}
ULL getstr(int l,int r)
{
int len = r - l + 1;
return hash[r] - hash[l - 1] * mi[len];
}
char s[SZ];
void read(char s[])
{
memset(s,0,sizeof(s));
int tot = 0;
char a = getchar();
for(;a < 'a' || a > 'z';a = getchar());
for(;a >= 'a' && a <= 'z';a = getchar())
s[tot ++] = a;
}
int main()
{
int n,m,len1,len2;
scanf("%d%d%d%d",&n,&m,&len1,&len2);
mi[0] = 1;
for(int i = 1;i <= len1 + len2;i ++)
mi[i] = mi[i - 1] * base;
for(int i = 1;i <= n;i ++)
read(s),S1[i] = s;
for(int i = 1;i <= m;i ++)
read(s),S2[i] = s;
if(len1 < len2)
swap(S1,S2),swap(n,m),swap(len1,len2);
for(int i = 1;i <= m;i ++)
h[gethash(S2[i])] ++;
int len = (len1 + len2) >> 1;
LL ans = 0;
for(int i = 1;i <= n;i ++)
{
for(int j = 0;j < len * 2;j ++)
hash[j + 1] = hash[j] * base + S1[i][j % len] - 'a' + 1;
ULL x = 0;
for(int j = len;j < len1;j ++)
x = x * base + S1[i][j] - 'a' + 1;
for(int j = 1;j <= len;j ++)
{
ULL y = getstr(j,j + len1 - len - 1);
if(x == y)
{
ULL a = getstr(j + len1 - len,j + len - 1);
ans += h[a];
}
}
}
printf("%lld\n",ans);
return 0;
}