【KMP统计】 匹配统计
传送门
题意
给定字符串\(A,B\),给出\(Q\)个询问,每次询问给定一个\(x\),求满足\(A\)从当前位置开始的后缀子串与模板串\(B\)匹配的长度刚好是\(x\),
求在整个字符串中这样的位置数量是多少
数据范围
\(1 \leq N, M, Q, x \leq 200000\)
题解
二分做法:
-
枚举所有起点的\(i\)后缀,二分能够匹配的最大长度,每次只需要匹配当前点\(i\sim i+M\)的即可
-
将字符串通过\(hash\)预处理,判断\(hash\)值是否相等来判断两个字符串是否相等
-
维护\(cnt\),\(cnt[i]\)表示匹配长度为\(i\)下的后缀个数
-
预处理\(A、B\)的\(hash\)值为\(O(N+M)\),二分\(N\)次,每次\(logM\),即\(O(NlogM)\),\(Q\)个查询,每次\(O(1)\)
- 总的时间复杂度为\(O(NlogM + Q +M)\)
\(kmp\)做法:
-
\(kmp\)过程中只能求出来以\(j\)为终点的待匹配串匹配的长度
- 只要\(j\)匹配,\(next[j]\)就一定匹配,\(next[next[j]]\)也一定匹配,直至为\(0\)
-
维护一个\(cnt\),\(cnt_i\) 表示以\(i\)为终点的与\(B\)匹配长度\(\geq i\)的后缀个数
-
\(cnt[ne[i]]\)需要累积\(cnt[i]\)的值,如果在求的过程中累加复杂度会退化为\(O(N·M)\)
- 在求出所有当前的\(cnt[i]\)后,从\(M\)开始累计即可
-
\(cnt[i]-cnt[i+1]\)就是长度为\(i\)的后缀数量
Code
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<n;i++)
#define per(i,a,n) for(int i=n-1;i>=a;i--)
#define ll long long
#define ull unsigned long long
const int N=2e5+10;
int ne[N],cnt[N];
int n,m,q;
char A[N],B[N];
void kmp()
{
int j=0;
rep(i,2,m+1)
{
while(j && B[i] != B[j+1]) j=ne[j];
if(B[i]==B[j+1]) j++;
ne[i]=j;
}
j=0;
rep(i,1,n+1)
{
while(j && A[i]!=B[j+1]) j=ne[j];
if(A[i]==B[j+1]) j++;
cnt[j]++;
}
per(i,1,m+1) cnt[ne[i]]+=cnt[i];
}
void solve()
{
cin>>n>>m>>q;
cin>>A+1>>B+1;
int x;
kmp();
while(q--)
{
cin>>x;
cout<<cnt[x]-cnt[x+1]<<endl;
}
}
int main()
{
solve();
}

浙公网安备 33010602011771号