1. 程式人生 > >LOJ#6031. 「雅禮集訓 2017 Day1」字串

LOJ#6031. 「雅禮集訓 2017 Day1」字串

題解  注意 p*k=定值  那麼我們對k進行分情況討論

  當k很小的時候 這時候詢問次數會很多  我們考慮直接莫隊處理出這次詢問所對應子串區間 然後直接對應sam上的right集合即可

  當k很大的時候 這時候詢問次數會很少 我們暴力列舉每個區間是否屬於這次詢問 然後logn倍增查詢即可

#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;
}

  

#6031. 「雅禮集訓 2017 Day1」字串

記憶體限制:256 MiB時間限制:1000 ms標準輸入輸出 題目型別:傳統評測方式:文字比較  

題目描述

令 s 與 w為兩字串,定義:

  1. w[l, r]表示字串 w 在區間 [l, r]中的子串;
  2. w 在 ss中出現的頻率定義為w 在 s 中出現的次數;
  3. f(s, w, l, r) 表示 w[l, r] 在 s 中出現的頻率。

現在給定串 s,m 個區間 [l, r]和長度k,你要回答 q 個詢問,每個詢問給你一個長度為 k 的字串 w 和兩個整數 a, b求:

輸入格式

第一行四個整數 n, m, q, kn,m,q,k,nn 表示 ss 的長度。
接下來一行一個長為 ss 的字串 ss。
接下來 mm 行,每行兩個整數表示 l_i, r_ili,ri
接下來 qq 行,每行一個字串 ww,兩個整數 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