題意:給定一個字符串和個區間,次詢問,每次給定長度爲的字符串和區間,求對於所有,在內的子串在中出現次數之和。
看上去很不可做,但是有一個很難注意到的特殊性質:所有串長相等,所以。後面記
所以中的較小值是根號級別的,考慮數據分治
首先肯定要先建出的後綴自動機
當時,字符串很短,直接開個vector記錄所有區間出現的位置,然後暴力枚舉的子串,在對應的vector用和二分一下算出有多少個區間,乘上在後綴自動機上的size。複雜度
當時,詢問很少,可以每次單獨處理。每次讀入後先預處理出的每個前綴 最長的 是的子串 的 後綴長度。
然後暴力把中的區間掛到上,從左到右掃一遍,設當前處理,如果,說明這個子串沒有出現過,直接跳過;否則在fail樹上倍增找到最靠上的滿足的結點,這個子串就出現了次。複雜度
某個的點用SOLVE2會卡常,所以特判成了SOLVE1
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cctype>
#include <vector>
#include <algorithm>
#define MAXN 200005
using namespace std;
int ch[MAXN][26],fa[MAXN],tot=1,las=1;
int len[MAXN],siz[MAXN];
void insert(int c)
{
int p=las,cur=++tot;
len[cur]=len[las]+1,las=cur;
for (;p&&!ch[p][c];p=fa[p]) ch[p][c]=cur;
if (!p) fa[cur]=1;
else
{
int q=ch[p][c];
if (len[q]==len[p]+1) fa[cur]=q;
else
{
int _q=++tot;
len[_q]=len[p]+1;
fa[_q]=fa[q],fa[q]=fa[cur]=_q;
memcpy(ch[_q],ch[q],sizeof(ch[q]));
for (;ch[p][c]==q;p=fa[p]) ch[p][c]=_q;
}
}
siz[cur]=1;
}
int a[MAXN],c[MAXN],up[MAXN][20];
inline void build(int n)
{
for (int i=1;i<=tot;i++) ++c[len[i]];
for (int i=1;i<=n;i++) c[i]+=c[i-1];
for (int i=tot;i;i--) a[c[len[i]]--]=i;
for (int i=1;i<=tot;i++)
{
up[a[i]][0]=fa[a[i]];
for (int j=1;j<20;j++) up[a[i]][j]=up[up[a[i]][j-1]][j-1];
}
for (int i=tot;i;i--) if (fa[a[i]]) siz[fa[a[i]]]+=siz[a[i]];
}
int n,m,k,q,l[MAXN],r[MAXN];
char s[MAXN],w[MAXN];
typedef long long ll;
namespace SOLVE1
{
vector<int> lis[405][405];
int pos[MAXN];
void main()
{
for (int i=1;i<=m;i++) lis[l[i]][r[i]].push_back(i);
while (q--)
{
int a,b;
scanf("%s%d%d",w+1,&a,&b);
++a,++b;
ll ans=0;
for (int i=1;i<=k;i++)
{
int now=1;
for (int j=i;j<=k;j++)
{
now=ch[now][w[j]-'a'];
if (!now) break;
ans+=(ll)siz[now]*(upper_bound(lis[i][j].begin(),lis[i][j].end(),b)-upper_bound(lis[i][j].begin(),lis[i][j].end(),a-1));
}
}
printf("%lld\n",ans);
}
}
}
namespace SOLVE2
{
vector<int> lis[MAXN];
int pos[MAXN],maxl[MAXN];
void main()
{
while (q--)
{
int a,b;
scanf("%s%d%d",w+1,&a,&b);
++a,++b;
ll ans=0;
int now=1,curl=0;
for (int i=a;i<=b;i++) lis[r[i]].push_back(l[i]);
for (int i=1;i<=k;i++)
{
while (now&&!ch[now][w[i]-'a']) now=fa[now],curl=len[now];
now=ch[now][w[i]-'a'],++curl;
if (!now) now=1,curl=0;
pos[i]=now,maxl[i]=curl;
}
for (int p=1;p<=k;p++)
for (int j=0;j<(int)lis[p].size();j++)
{
int u=pos[p],lim=p-lis[p][j]+1;
if (maxl[p]<lim) continue;
for (int i=19;i>=0;i--)
if (len[up[u][i]]>=lim)
u=up[u][i];
ans+=siz[u];
}
printf("%lld\n",ans);
for (int i=a;i<=b;i++) lis[r[i]].clear();
}
}
}
int main()
{
scanf("%d%d%d%d",&n,&m,&q,&k);
scanf("%s",s+1);
for (int i=1;i<=n;i++) insert(s[i]-'a');
build(n);
for (int i=1;i<=m;i++) scanf("%d%d",&l[i],&r[i]),++l[i],++r[i];
if (k<=q)
SOLVE1::main();
else
SOLVE2::main();
return 0;
}