zoukankan      html  css  js  c++  java
  • loj6031.「雅礼集训 2017 Day1」字符串

    题意

    注意到询问串的长度(k)是给定的,同时(sumlimits len_w=kqleqslant10^5),我们发现(k,q)之间一个大了另一个必定会小,因此我们对(k)分类讨论:
    首先肯定要对(s)建一个后缀自动机,对每个点维护(endpos)集合的大小。

    (kgeqslantsqrt{n})

    这时(qleqslantsqrt{n}),我们直接在(SAM)暴力匹配(w),找出所有(w)的前缀对应的节点,之后枚举询问,倍增跳到(w[l_i...r_i])这个节点,将答案加上该节点的(endpos)集合大小即可。

    (k<sqrt{n})

    这时(m)组询问中的种类很少,我们可以枚举(w)的所有子串,算出它在([l,r])这段询问区间中出现的次数,乘上它的答案加到答案中。

    code:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    #define re register
    #define pii pair<int,int>
    #define mkp make_pair
    #define fir first
    #define sec second
    const int maxn=2e5+10;
    const int maxt=410;
    int n,m,Q,K,tot,cnt_edge,t;
    int head[maxn],size[maxn],pos[maxn],posl[maxn];
    int f[maxn][18];
    char s[maxn];
    inline int read()
    {
    	char c=getchar();re int res=0,f=1;
    	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    	while(c>='0'&&c<='9')res=res*10+c-'0',c=getchar();
    	return res*f;
    }
    struct edge{int to,nxt;}e[maxn];
    inline void add_edge(int u,int v)
    {
    	e[++cnt_edge].nxt=head[u];
    	head[u]=cnt_edge;
    	e[cnt_edge].to=v;
    }
    struct Query{int l,r;}qr[maxn];
    struct SAM
    {
    	int last,tot;
    	int fa[maxn],len[maxn];
    	int ch[maxn][26];
    	SAM(){last=tot=1;}
    	inline void add(int c)
    	{
    		re int now=++tot;len[now]=len[last]+1;
    		re int p=last;last=now;
    		while(p&&!ch[p][c])ch[p][c]=now,p=fa[p];
    		if(!p){fa[now]=1;return;}
    		re int q=ch[p][c];
    		if(len[q]==len[p]+1)fa[now]=q;
    		else
    		{
    			re int nowq=++tot;len[nowq]=len[p]+1;
    			memcpy(ch[nowq],ch[q],sizeof(ch[q]));
    			fa[nowq]=fa[q];fa[q]=fa[now]=nowq;
    			while(p&&ch[p][c]==q)ch[p][c]=nowq,p=fa[p];
    		}
    	}
    }sam;
    void dfs(int x)
    {
    	for(re int i=1;i<=17;i++)f[x][i]=f[f[x][i-1]][i-1];
    	for(re int i=head[x];i;i=e[i].nxt)
    	{
    		re int y=e[i].to;
    		f[y][0]=x;dfs(y);
    		size[x]+=size[y];
    	}
    }
    inline void solve1()
    {
    	vector<int>a[maxt][maxt];
    	for(int i=1;i<=m;i++)a[qr[i].l][qr[i].r].push_back(i);
    	while(Q--)
    	{
    		scanf("%s",s+1);
    		int l=read()+1,r=read()+1;
    		ll res=0;
    		for(int i=1;i<=K;i++)
    			for(int j=i,now=1;j<=K;j++)
    			{
    				now=sam.ch[now][s[j]-'a'];
    				if(!now)break;
    				int ql=lower_bound(a[i][j].begin(),a[i][j].end(),l)-a[i][j].begin();
    				int qr=upper_bound(a[i][j].begin(),a[i][j].end(),r)-a[i][j].begin();
    				res+=1ll*(qr-ql)*size[now];
    			}
    		printf("%lld
    ",res);
    	}
    }
    inline int find(int l,int r)
    {
    	re int now=pos[r];
    	for(re int i=17;~i;i--)if(sam.len[f[now][i]]>=min(r-l+1,posl[r]))now=f[now][i];
    	return now;
    }
    inline int solve(int l,int r)
    {
    	if(!pos[r]||posl[r]<(r-l+1))return 0;;
    	re int now=find(l,r);
    	if(sam.len[now]>=r-l+1)return size[now];
    	else return 0;
    }
    inline void solve2()
    {
    	while(Q--)
    	{
    		scanf("%s",s+1);
    		re int l=read()+1,r=read()+1;
    		re int now=1,nowl=0,res=0;
    		for(re int i=1;i<=K;i++)
    		{
    			re int c=s[i]-'a';
    			while(!sam.ch[now][c]&&now)now=sam.fa[now],nowl=sam.len[now];
    			if(!now){now=1;pos[i]=1;nowl=0;posl[i]=0;continue;}
    			now=sam.ch[now][c];pos[i]=now;
    			nowl++;posl[i]=nowl;
    		}	
    		for(re int i=l;i<=r;i++)res+=solve(qr[i].l,qr[i].r);
    		printf("%d
    ",res);
    	}
    }
    int main()
    {
    	//freopen("test.in","r",stdin);
    	//freopen("test.out","w",stdout);
    	n=read(),m=read(),Q=read(),K=read();t=330;
    	scanf("%s",s+1);
    	for(re int i=1;i<=n;i++)sam.add(s[i]-'a'),size[sam.last]=1;
    	for(re int i=2;i<=sam.tot;i++)add_edge(sam.fa[i],i);
    	dfs(1);
    	for(re int i=1;i<=m;i++)qr[i].l=read()+1,qr[i].r=read()+1;
    	if(K<=t)solve1();
    	else solve2();
    	return 0;
    } 
    
  • 相关阅读:
    Java复习笔记8--内部类
    Java复习笔记7--Java封装
    Java复习笔记6--Final&Static
    Java复习笔记5--equals方法总结
    Java复习笔记4--实现多重继承
    Java复习笔记3--强制类型转换
    Java复习笔记2--匿名类和多态
    python版本管理--pyenv
    gensim自然语言处理(续)
    gensim自然语言处理
  • 原文地址:https://www.cnblogs.com/nofind/p/12149765.html
Copyright © 2011-2022 走看看