题解 -
s
x
y
z
5.14
\mathrm{sxyz \ 5.14}
sxyz 5.14 膜你赛
C
\mathrm{C}
C
题目意思
- 给你
n
n
n个字符串以及
m
m
m对字符串
p
,
q
p,q
p,q。问
n
n
n个字符串中有几个串的前缀为
p
p
p,后缀为
q
q
q
-
n
,
m
,
∑
(
∣
s
∣
)
≤
1
0
5
n,m,\sum(|s|) \leq 10^5
n,m,∑(∣s∣)≤105
S
o
l
\mathrm{Sol}
Sol
- 前置知识:Trie树+扫描线
- 对于这些有两个限制的问题我们考虑限定一个条件然后用数据结构去维护另一个限制。
- 比如对于这道题目,我们先固定
p
p
p,再去寻找合法的
q
q
q的串。我们首先对于字符串排序(使得那些具有相同前缀的串在一个区间),这个在
T
r
i
e
Trie
Trie树里可以维护。
- 这样子离线下来,现在前缀固定,只要在这个区间里寻找合法的后缀匹配串,这就变成经典的扫描线问题了,随意维护一下就可以了。
- 复杂度
O
(
n
log
n
)
O(n \log n)
O(nlogn)
C
o
d
e
\mathrm{Code}
Code
#include <bits/stdc++.h>
#define pb push_back
using namespace std;
inline int read()
{
int sum=0,ff=1;
char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-') ff=-1;
ch=getchar();
}
while(isdigit(ch))
sum=sum*10+(ch^48),ch=getchar();
return sum;
}
const int N=2000005;
int n,m,cnt,ans[N];
struct Node
{
int l,r,op,id;
};
vector<Node> q[N];
inline int rbq(char c)
{
if(c=='A') return 0;
if(c=='U') return 1;
if(c=='G') return 2;
if(c=='C') return 3;
}
struct Trie
{
int tot,cnt,ch[N][4],dfn[N],id[N],L[N],R[N];
Trie(){cnt=tot=0;}
vector<int> M[N];
inline void insert(string s,int id)
{
int u=0;
int len=s.length();
for ( int i=0;i<len;i++ )
{
int c=rbq(s[i]);
if(!ch[u][c]) ch[u][c]=++cnt;
u=ch[u][c];
}
M[u].pb(id);
}
inline void dfs(int u)
{
L[u]=tot+1;
for ( int i=0;i<M[u].size();i++ )
{
int v=M[u][i];
dfn[++tot]=v;
id[v]=tot;
}
for ( int i=0;i<=3;i++ )
if(ch[u][i])
dfs(ch[u][i]);
R[u]=tot;
}
};
Trie t1,t2;
struct Bit
{
#define lowbit(x) x&(-x)
int C[N];
inline void add(int x,int v)
{
if(x<=0) return;
while(x<=t2.tot)
{
C[x]+=v;
x+=lowbit(x);
}
}
inline int ask(int x)
{
if(x<=0) return 0;
int ans=0;
while(x)
{
ans+=C[x];
x-=lowbit(x);
}
return ans;
}
};
Bit T;
int main()
{
n=read();
m=read();
for ( int i=1;i<=n;i++ )
{
string jb;
cin>>jb;
t1.insert(jb,i);
reverse(jb.begin(),jb.end());
t2.insert(jb,i);
}
t1.dfs(0);
t2.dfs(0);
for ( int Q=1;Q<=m;Q++ )
{
string a,b;
cin>>a>>b;
reverse(b.begin(),b.end());
int l=a.length();
int u1=0,u2=0;
for ( int i=0;i<l;i++ )
{
u1=t1.ch[u1][rbq(a[i])];
if(!u1) break;
}
l=b.length();
for ( int i=0;i<l;i++ )
{
u2=t2.ch[u2][rbq(b[i])];
if(!u2) break;
}
if(!u1||!u2) continue;
Node A={t2.L[u2],t2.R[u2],-1,Q};
Node B={t2.L[u2],t2.R[u2],1,Q};
q[t1.L[u1]-1].pb(A);
q[t1.R[u1]].pb(B);
}
for ( int i=0;i<=t2.tot;i++ ) T.C[i]=0;
for ( int i=1;i<=t1.tot;i++ )
{
T.add(t2.id[t1.dfn[i]],1);
for ( int j=0;j<q[i].size();j++ )
{
Node v=q[i][j];
ans[v.id]+=v.op*(T.ask(v.r)-T.ask(v.l-1));
}
}
for ( int i=1;i<=m;i++ ) printf("%d\n",ans[i]);
return 0;
}