列表

详情


NC237662. 葫芦的考验之定位子串

描述

给出一个只包含小写字母的字符串s
q次询问,每次询问子串s中的出现次数。

输入描述

第一行一个只包含小写字母的字符串.
第二行一个正整数代表询问数
接下来q行,每行两个整数,表示一个询问

输出描述

对于每个询问,输出一行一个整数表示答案。

示例1

输入:

abcbc
3
2 2
2 3
3 4

输出:

2
2
1

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++(g++ 7.5.0) 解法, 执行用时: 366ms, 内存消耗: 97484K, 提交时间: 2023-04-14 15:07:31

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e6+5;
char s[N];

int tot=1,fa[N<<1],len[N<<1],ch[N<<1][26];
int last=1,p,np,q,nq;
int ri[N<<1];
int v[N<<1],sa[N<<1];
int st[N][19],id[N];
void extend(int c,int k)
{
    len[np=++tot]=len[last]+1;
    for(p=last;p && !ch[p][c]; p=fa[p]) ch[p][c]=np;
    if(!p) fa[np]=1;
    else
    {
        q=ch[p][c];
        if(len[q]==len[p]+1) fa[np]=q;
        else
        {
            len[nq=++tot]=len[p]+1;
            memcpy(ch[nq],ch[q],sizeof(ch[nq]));
            fa[nq]=fa[q];
            fa[q]=fa[np]=nq;
            for(;ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
        }
    }
    
    last=np;
    ri[last]=1;
    id[k]=last;
}
int query(int l,int r)
{
	int u=id[r];
	for(int i=18;i>=0;i--)
		if(len[st[u][i]]>=r-l+1) u=st[u][i];
	return ri[u];
}
int main()
{
    scanf("%s",s+1);
    int n=strlen(s+1);
    for(int i=1;i<=n;++i) extend(s[i]-'a',i);
    for(int i=1;i<=tot;++i) st[i][0]=fa[i];
    for(int i=1;i<=tot;++i) v[len[i]]++;
    for(int i=1;i<=n;++i) v[i]+=v[i-1];
    for(int i=1;i<=tot;++i) sa[v[len[i]]--]=i;
    for(int i=tot;i;--i) ri[fa[sa[i]]]+=ri[sa[i]];
    for(int j=1;j<=18;j++)
    	for(int i=1;i<=tot;i++)
    		st[i][j]=st[st[i][j-1]][j-1];
    int q;scanf("%d",&q);
    while(q--) 
    {
    	int l,r;scanf("%d%d",&l,&r);
    	printf("%d\n",query(l,r));
	}
}

上一题