1972: #6031. 「雅礼集训 2017 Day1」字符串

题目描述

令 s ss 与 w ww 为两字符串,定义:

  1. w[l,r] w[l, r]w[l,r] 表示字符串 w ww 在区间 [l,r] [l, r][l,r] 中的子串;
  2. w ww 在 s ss 中出现的频率定义为w ww 在 s ss 中出现的次数;
  3. f(s,w,l,r) f(s, w, l, r)f(s,w,l,r) 表示 w[l,r] w[l, r]w[l,r] 在 s ss 中出现的频率。

比如 f(ababa,aba,1,3)=2。

现在给定串 s ss,m mm 个区间 [l,r] [l, r][l,r] 和长度 k kk,你要回答 q qq 个询问,每个询问给你一个长度为 k kk 的字符串 w ww 和两个整数 a,b a, ba,b,求:

∑i=abf(s,w,li,ri) \sum\limits_{i = a} ^ b f(s, w, l_i, r_i)i=a∑bf(s,w,li,ri)

输入

第一行四个整数 n,m,q,k n, m, q, kn,m,q,k,n nn 表示 s ss 的长度。
接下来一行一个长为 s ss 的字符串 s ss。
接下来 m mm 行,每行两个整数表示 li,ri l_i, r_ili,ri。
接下来 q qq 行,每行一个字符串 w ww,两个整数 a,b a, ba,b。

输出

对于每个询问一行,输出答案。

样例输入 

8 5 3 3
abacdaba
0 2
1 2
0 0
2 2
1 2
dab 1 4
bac 2 3
eeb 1 3

样例输出 

7
3
2
​

提示

对于 10% 10\%10% 的数据,n,m,k,q≤10 n, m, k, q \leq 10n,m,k,q≤10;
对于 30% 30\%30% 的数据,满足 n,m,k,q≤102 n, m, k, q \leq 10 ^ 2n,m,k,q≤102;
对于 50% 50\%50% 的数据,满足 n,m,k,q≤104 n, m, k, q \leq 10 ^ 4n,m,k,q≤104;
对于 100% 100\%100% 的数据,满足 n,m,k,q≤105,∑w≤105 n, m, k, q \leq 10 ^ 5, \sum w \leq 10 ^ 5n,m,k,q≤105,∑w≤105,字符串由小写英文字母构成。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <stack>
#include <queue>
#include <cmath>
#include <set>
#include <map>
#define mp make_pair
#define pb push_back
#define pii pair<int,int>
#define link(x) for(edge *j=h[x];j;j=j->next)
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,r,l) for(int i=r;i>=l;i--)
const int MAXN=2e5+10;
const double eps=1e-8;
#define ll long long
using namespace std;
struct edge{int t;edge*next;}e[MAXN],*h[MAXN],*o=e;
void add(int x,int y){o->t=y;o->next=h[x];h[x]=o++;}
ll read(){
    ll x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    return x*f;
}
int n,m,q,k;
char str[MAXN];
int cur,rt,cnt,fa[MAXN],dis[MAXN],ch[MAXN][26],sz[MAXN];
  
void built(int x){
    int last=cur;cur=++cnt;dis[cur]=dis[last]+1;int p=last;sz[cur]=1;
    for(;p&&!ch[p][x];p=fa[p])ch[p][x]=cur;
    if(!p)fa[cur]=rt;
    else{
    int q=ch[p][x];
    if(dis[q]==dis[p]+1)fa[cur]=q;
    else{
        int nt=++cnt;dis[nt]=dis[p]+1;
        memcpy(ch[nt],ch[q],sizeof(ch[q]));
        fa[nt]=fa[q];fa[q]=fa[cur]=nt;
        for(;ch[p][x]==q;p=fa[p])ch[p][x]=nt;
    }
    }
}
int f[MAXN][21],dep[MAXN];
  
void dfs(int x,int pre,int deep){
    f[x][0]=pre;dep[x]=deep+1;
    inc(i,1,20)f[x][i]=f[f[x][i-1]][i-1];
    link(x){
    dfs(j->t,x,deep+1);
    sz[x]+=sz[j->t];
    }
}
  
int calc(int x,int t){
    int y=x;
    for(int i=20;i>=0;i--){
    if(dis[f[y][i]]>=t)y=f[y][i];
    }
    return sz[y];
}
  
typedef struct node{
    string s;int l,r,id;
}node;
node d[MAXN];
typedef struct Node{
    int l,r,id;
}Node;
Node que[MAXN];
int P[MAXN],Sz;
bool cmp(node aa,node bb){
    if(P[aa.l]==P[bb.l])return aa.r<bb.r;
    else return P[aa.l]<P[bb.l];
}
bool cmp1(Node aaa,Node bbb){
    return aaa.r<bbb.r;
}
int num[405][405],Rt[MAXN],Len[MAXN];
ll ans[MAXN];
int main(){
    ios::sync_with_stdio(false);
    cin>>n>>m>>q>>k;
    Sz=sqrt(m);
    inc(i,1,m)P[i]=(i-1)/Sz+1;
    int base=sqrt(q*k);
    cin>>str;
    cur=rt=cnt=1;
    inc(i,0,n-1)built(str[i]-'a');
    inc(i,1,cnt)add(fa[i],i);
    dfs(rt,0,0);
    inc(i,1,m)cin>>que[i].l>>que[i].r,que[i].l++,que[i].r++,que[i].id=i;
    inc(i,1,q)cin>>d[i].s>>d[i].l>>d[i].r,d[i].l++,d[i].r++,d[i].id=i;
    if(k<=base){
    sort(d+1,d+q+1,cmp);
    int L=1;int R=0;
    inc(i,1,q){
        while(R<d[i].r){
        R++;num[que[R].l][que[R].r]++;
        }
        while(R>d[i].r){
        num[que[R].l][que[R].r]--;R--;
        }
        while(L>d[i].l){
        L--;
        num[que[L].l][que[L].r]++;
        }
        while(L<d[i].l){
        num[que[L].l][que[L].r]--;L++;
        }
        int temp=rt;int len1=0;
        for(int j=0;j<k;j++){
        int t1=d[i].s[j]-'a';
        if(ch[temp][t1])temp=ch[temp][t1],len1++;
        else{
            int pp=temp;
            for(;pp&&!ch[pp][t1];pp=fa[pp]);
            if(!pp)temp=rt,len1=0;else temp=ch[pp][t1],len1=dis[pp]+1;
        }
        /*for(int w=j;w>=j-len1+1;w--){
            if(!num[w+1][j+1])continue;
            ans[d[i].id]+=1ll*num[w+1][j+1]*calc(temp,j-w+1);
        }*/
        int len2=len1;int ppp=temp;
        while(ppp!=rt){
            for(int w=j-dis[fa[ppp]];w>=j-len2+1;w--)ans[d[i].id]+=1ll*num[w+1][j+1]*sz[ppp];
            ppp=fa[ppp];len2=dis[ppp];
        }
        }
    }
    inc(i,1,q)printf("%lld\n",ans[i]);
    return 0;
    }
    else{
    sort(que+1,que+m+1,cmp1);
    int tot=0;
    inc(i,1,q)Rt[i]=rt,Len[i]=0;
    inc(i,1,m){
        while(tot<k&&tot<que[i].r){
        inc(j,1,q){
            int t1=d[j].s[tot]-'a';int temp=Rt[j];
            if(ch[temp][t1])Rt[j]=ch[temp][t1],Len[j]++;
            else{
            int pp=temp;
            for(;pp&&!ch[pp][t1];pp=fa[pp]);
            if(!pp)Rt[j]=rt,Len[j]=0;else Rt[j]=ch[pp][t1],Len[j]=dis[pp]+1;
            }
        }
        tot++;
        }
        inc(j,1,q){
        if(que[i].id>=d[j].l&&que[i].id<=d[j].r){
            if(Len[j]<que[i].r-que[i].l+1)continue;
            ans[j]+=calc(Rt[j],que[i].r-que[i].l+1);
        }
        }
    }
    inc(i,1,q)printf("%lld\n",ans[i]);
    }
    return 0;
}

  • 12
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值