您的位置:首页 > 其它

4084: [Sdoi2015]双旋转字符串

2017-02-16 21:27 204 查看

4084: [Sdoi2015]双旋转字符串

Time Limit: 10 Sec  Memory Limit: 512 MB
Submit: 394  Solved: 161

[Submit][Status][Discuss]

Description

给定两个字符串集合 S 和 T 。其中 S 中的所有字符串长度都恰好为 N ,而 T 中所有字符串长度都恰好为 M 。且 N+M 恰好为偶数。
如果记 S 中字符串全体为 S1,S2,...,STotalS ,而 T 中字符串全体为 T1,T2,...,TTotalT 。
现在希望知道有多少对 <i,j> ,满足将 Si 和 Tj 拼接后得到的字符串 Si+Tj 满足双旋转性。
一个长度为偶数字符串 W 可以表示成两段长度相同的字符串的拼接,即 W=U+V。如果 V 可以通过 U 旋转得到,则称 W 是满足双旋转性的。比如说字符串 U=“vijos”可以通过旋转得到“ijosv”,“josvi”,“osvij” 或“svijo”。那么“vijosjosvi”就是满足双旋转性的字符串。

Input

第一行输入四个正整数,分别为 TotalS,TotalT,N 和 M,依次表示集合 S 的大小,集合 T 的大小,集合 S 中字符串的长度和集合 T 中字符串的长度。
之后 TotalS 行,依次给出 S 中所有的字符串 Si,1≤i≤TotalS。保证每一个字符串长度都恰为 N ,且字符串只由 26 个小写字母组成。
之后 TotalT 行,依次给出 T 中所有的字符串 Ti,1≤i≤TotalT。保证每一个字符串长度都恰为 M ,且字符串只由 26 个小写字母组成。
1≤N≤100;1≤M≤100;1≤TotalS≤100;1≤Total^T≤100,2≤N*TotalS+M*TotalT≤4×10^6,N>=M

Output

输出一个整数,表示满足要求的数字对 <i,j> 有多少个。

Sample Input

4 4 7 3

vijosvi

josvivi

vijosos

ijosvsv

jos

vij

ijo

jos

Sample Output

6

HINT

Source



[Submit][Status][Discuss]


一开始题意没读好,结果做不出来。。。。

大概是要统计有多少对<i,j>使得串Si + Tj左右两半循环同构

不妨假设N >= M,反之情况类似

对于T中的每个字符串,先hash一下存在一个桶里面

暴力枚举S中的每个字符串,假设当前枚举的是Si

对于这个串,记mid = (N + M) / 2,Si的mid + 1 ~ N位在合并以后显然是给右边的半部分用的

可以在1 ~ mid位中暴力查找一下那些位置往后N - mid位与这个短串相等

每次找到一个位置,对于1 ~ mid的剩下的字符,后半部在前前半部放后显然就确定了Tj

这时候只要在桶里面查询一下这样的Tj有多少就行了

记得统计的时候不能重复,就是一类Tj对于每个Si只能用一次

用了双hash + 离散化处理这个桶,,O(|S| * logM),复杂度有点感人。。。#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;

const int maxn = 4E6 + 4;
const int mod1 = 1000000007;
const int mod2 = 99999983;
typedef long long LL;

struct Hash{
int h1,h2; Hash(){h1 = h2 = 0;}
Hash(int h1,int h2): h1(h1),h2(h2){}
Hash operator * (const Hash &B)
{
Hash ret;
ret.h1 = 1LL * h1 * B.h1 % mod1;
ret.h2 = 1LL * h2 * B.h2 % mod2;
return ret;
}
Hash operator *= (const Hash &B)
{
h1 = 1LL * h1 * B.h1 % mod1;
h2 = 1LL * h2 * B.h2 % mod2;
}
Hash operator += (const int &B)
{
h1 += B; if (h1 >= mod1) h1 -= mod1;
h2 += B; if (h2 >= mod2) h2 -= mod2;
}
Hash operator += (const Hash &B)
{
h1 += B.h1; if (h1 >= mod1) h1 -= mod1;
h2 += B.h2; if (h2 >= mod2) h2 -= mod2;
}
Hash operator -= (const Hash &B)
{
h1 -= B.h1; if (h1 < 0) h1 += mod1;
h2 -= B.h2; if (h2 < 0) h2 += mod2;
}
bool operator < (const Hash &B) const
{
if (h1 < B.h1) return 1;
if (h1 > B.h1) return 0;
return h2 < B.h2;
}
bool operator == (const Hash &B) const {return h1 == B.h1 && h2 == B.h2;}
bool operator != (const Hash &B) const {return h1 != B.h1 || h2 != B.h2;}
}p;

int n,m,ta,tb,mid,cur,Cnt;
char ch[maxn];

vector <string> A,B;
vector <Hash> mi,v,h;
vector <int> cnt,vis;

Hash GetHash(int L,int R)
{
Hash ret; if (L > R) return ret;
ret = h[R]; if (L > 0) ret -= (h[L - 1] * mi[R - L + 1]);
return ret;
}

void Solve1()
{
int siz = n - mid; LL Ans = 0; mi.push_back(Hash(1,1));
for (int i = 1; i <= n; i++) mi.push_back(mi[i - 1] * p);
for (int i = 0; i < tb; i++)
{
string &s = B[i]; Hash now;
for (int j = 0; j < m; j++) now *= p,now += s[j];
v.push_back(now);
}
sort(v.begin(),v.end()); cnt.push_back(1);
for (int i = 1; i < v.size(); i++)
if (v[i] == v[i - 1]) ++cnt[cur];
else v[++cur] = v[i],cnt.push_back(1);
while (v.size() - 1 > cur) v.pop_back();
for (int i = 0; i <= cur; i++) vis.push_back(0);
for (int i = 0; i < n; i++) h.push_back(Hash(0,0));
for (int i = 0; i < ta; i++)
{
string &s = A[i]; Hash now; ++Cnt;
for (int j = 0; j < mid; j++) now *= p,now += s[j],h[j] = now;
now = Hash(0,0);
for (int j = mid; j < n; j++) now *= p,now += s[j];
for (int j = 0; j <= mid - siz; j++)
{
if (GetHash(j,j + siz - 1) != now) continue;
Hash Now = GetHash(j + siz,mid - 1);
Now *= mi[j]; Now += GetHash(0,j - 1);
int pos = lower_bound(v.begin(),v.end(),Now) - v.begin();
if (pos < v.size() && v[pos] == Now && vis[pos] != Cnt) Ans += 1LL * cnt[pos],vis[pos] = Cnt;
}
}
cout << Ans << endl;
}

void Solve2()
{
int siz = m - mid; LL Ans = 0; mi.push_back(Hash(1,1));
for (int i = 1; i <= m; i++) mi.push_back(mi[i - 1] * p);
for (int i = 0; i < ta; i++)
{
string &s = A[i]; Hash now;
for (int j = 0; j < n; j++) now *= p,now += s[j];
v.push_back(now);
}
sort(v.begin(),v.end()); cnt.push_back(1);
for (int i = 1; i < v.size(); i++)
if (v[i] == v[i - 1]) ++cnt[cur];
else v[++cur] = v[i],cnt.push_back(1);
while (v.size() - 1 > cur) v.pop_back();
for (int i = 0; i <= cur; i++) vis.push_back(0);
for (int i = 0; i < m; i++) h.push_back(Hash(0,0));
for (int i = 0; i < tb; i++)
{
string &s = B[i]; Hash now; ++Cnt;
for (int j = siz; j < m; j++) now *= p,now += s[j],h[j] = now;
now = Hash(0,0);
for (int j = 0; j < siz; j++) now *= p,now += s[j];
for (int j = siz; j <= m - siz; j++)
{
if (GetHash(j,j + siz - 1) != now) continue;
Hash Now = GetHash(j + siz,m - 1);
Now *= mi[j - siz]; Now += GetHash(siz,j - 1);
int pos = lower_bound(v.begin(),v.end(),Now) - v.begin();
if (pos < v.size() && v[pos] == Now && vis[pos] != Cnt) Ans += 1LL * cnt[pos],vis[pos] = Cnt;
}
}
cout << Ans << endl;
}

int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
#endif

p.h1 = 233; p.h2 = 131;
cin >> ta >> tb >> n >> m; mid = n + m >> 1;
for (int i = 0; i < ta; i++)
{
scanf("%s",ch); string s;
for (int j = 0; j < n; j++) s += ch[j];
A.push_back(s);
}
for (int i = 0; i < tb; i++)
{
scanf("%s",ch); string s;
for (int j = 0; j < m; j++) s += ch[j];
B.push_back(s);
}
if (n >= m) Solve1(); else Solve2();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: