A19506. 谐音替换(replace)
题目描述
谐音替换(replace)
题目描述
小 W 是一名喜欢语言学的算法竞赛选手。在语言学中,谐音替换是指将原有的字词替换为读音相同或相近的字词。小 W 发现,谐音替换的过程可以用字符串来进行描述。具体地,小 W 将谐音替换定义为以下字符串问题:
给定 n 个字符串二元组,第 i(1 ≤ i ≤ n)个字符串二元组为 (si,1, si,2),满足 |si,1| = |si,2|,其中 |s| 表示字符串 s 的长度。
对于字符串 s,定义 s 的替换如下:
对于 s 的某个子串 y,若存在 1 ≤ i ≤ n 满足 y = si,1,则将 y 替换为 y' = si,2。具体地,设 s = x + y + z,其中 x 和 z 可以为空,“+” 表示字符串拼接,则 s 的替换将得到字符串 s' = x + y' + z。
小 W 提出了 q 个问题,第 j(1 ≤ j ≤ m)个问题会给定两个不同的字符串 tj,1, tj,2,她想知道有多少种字符串 tj,1 的替换能够得到字符串 tj,2。两种 s 的替换不同当且仅当子串 y 的位置不同或用于替换的二元组 (si,1, si,2) 不同,即 x,z 不同或 i 不同。你需要回答小 W 提出的所有问题。
输入格式
从文件 replace.in 中读入数据。
输入的第一行包含两个正整数 n, q,分别表示字符串二元组的数量和小 W 提出的问题的数量。
输入的第 i+1(1 ≤ i ≤ n)行包含两个字符串 si,1, si,2,表示第 i 个字符串二元组。
输入的第 j+n+1(1 ≤ j ≤ q)行包含两个字符串 tj,1, tj,2,表示小 W 提出的第 j 个问题。
输出格式
输出到文件 replace.out 中。
输出 q 行,其中第 j(1 ≤ j ≤ q)行包含一个非负整数,表示替换后得到字符串 tj,2 的字符串 tj,1 的替换的数量。
样例 1 输入
4 2
xabcx xadex
ab cd
bc de
aa bb
xabcx xadex
aaaa bbbb样例 1 输出
2
0
样例 1 解释
对于小 W 的第一个询问,共有 2 种 t1,1 的替换能够得到 t1,2:
1.令 x,z 均为空串,y = xabcx,i=1,则 y' = xadex,替换后得到 xadex;
2.令 x = xa,y = bc,z = x,i=3,则 y' = de,替换后得到 xadex。
样例 2 输入
3 4
a b
b c
c d
aa bb
aa b
a c
b a样例 2 输出
0
0
0
0样例 3
见选手目录下的 replace/replace3.in 与 replace/replace3.ans。
该样例满足测试点 11, 12 的约束条件。
样例 4
见选手目录下的 replace/replace4.in 与 replace/replace4.ans。
该样例满足测试点 15, 16 的约束条件。
数据范围
设 L1 =∑n i=1 |si,1| + |si,2|,L2 = ∑q j=1 |tj,1| + |tj,2|。对于所有测试数据,保证:
1 ≤ n, q ≤ 2 × 105;
2 ≤ L1, L2≤ 5 × 106;
对于所有 1 ≤ i ≤ n,si,1, si,2 均仅包含小写英文字母,且 |si,1| = |si,2|;
对于所有 1 ≤ j ≤ q,tj,1, tj,2 均仅包含小写英文字母,且 tj,1 ≠ tj,2。

特殊性质A:q=1。
特殊性质B:定义字符串s为特别的,当且仅当字符串s仅包含字符a和b,且字符b在s中出现恰好一次。对于所有1 ≤ i ≤ n,si,1, si,2 均为特别的,且对于所有
1≤j≤q,tj,1,tj,2均为特别的。
参考答案
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
const int P = 1e9+7, Q=1e9+9, B=457, C=997;
ll next_hash (ll prev, int chr)
{
ll a = prev >> 32, b = prev & -1u; chr ++;
a = (a * B + chr) % P;
b = (b * C + chr) % Q;
return (a << 32) | b;
}
const int maxl = 5002424;
const int maxn = 200083;
struct node
{ int pt, nxt [27]; }
trie [maxl*2+maxn];
struct pn
{
int rt;
unordered_map <ll, int> mp;
} pns [maxn];
int ctc, ptc;
char s [maxl], t [maxl];
void q_diff (int len, int& dnq, int& dxq)
{
int nq = len+1, xq=-1;
int i;
for (i=0; i<len; i++)
if (s [i] != t [i])
nq = min (nq, i), xq = max (xq, i);
dnq = nq; dxq = xq;
}
#define jnode(var,chr) if(trie[var].nxt[chr])var=trie[var].nxt[chr];else var=trie[var].nxt[chr]=++ctc
#define ord(ch) (ch=='#'?26:ch-'a')
void add_s (int idx)
{
scanf ("%s%s", s, t);
int len = strlen (s);
if (strcmp (s, t) == 0) return;
int nq, xq; q_diff (len, nq, xq);
int i, cur = 0;
for (i=nq; i<=xq; i++)
{
jnode (cur, ord (s [i]));
jnode (cur, ord (t [i]));
}
jnode (cur, 26);
for (; i<len; i++)
jnode (cur, ord (s [i]));
int pt = trie [cur] .pt;
if (pt == 0) pt = trie [cur] .pt = ++ptc;
cur = pns [pt] .rt;
if (cur == 0) cur = pns [pt] .rt = ++ctc;
for (i=nq-1; i>=0; i--)
jnode (cur, ord (s [i]));
trie [cur] .pt ++;
}
void dfs_pn (int rt, int cur, ll ch, int cn)
{
pns [rt] .mp [ch] = cn = trie [cur] .pt += cn;
int i, m;
for (i=0; i<27; i++)
if (m = trie [cur] .nxt [i])
dfs_pn (rt, m, next_hash (ch, i), cn);
}
ll hashes [maxl];
int query (void)
{
scanf ("%s%s", s, t);
int len = strlen (s);
if (strlen (t) != len) return 0;
int nq, xq; q_diff (len, nq, xq);
int i, cur = 0;
for (i=1; i<=nq; i++) hashes [i] = next_hash (hashes [i-1], ord (s [nq-i]));
for (i=nq; i<=xq; i++)
{
if (0 == (cur = trie [cur] .nxt [ord (s [i])])) return 0;
if (0 == (cur = trie [cur] .nxt [ord (t [i])])) return 0;
}
if (0 == (cur = trie [cur] .nxt [26])) return 0;
int ans = 0;
for (i=xq; i<len; i++)
{
if (trie [cur] .pt != 0)
{
int l = 0, r = nq;
pn& cpn = pns [trie [cur] .pt];
while (l < r)
{
int m = l+r+1 >> 1;
if (cpn.mp.count (hashes [m])) l = m;
else r = m-1;
}
ans += cpn.mp [hashes [l]];
}
if (i != len-1)
if (0 == (cur = trie [cur] .nxt [ord (t [i+1])]))
break;
}
return ans;
}
int main (void)
{
int n, q; scanf ("%d%d", &n, &q);
int i; for (i=1; i<=n; i++) add_s (i);
for (i=1; i<=ptc; i++) dfs_pn (i, pns [i] .rt, 0, 0);
for (i=1; i<=q; i++) printf ("%d\n", query ());
}