zoukankan      html  css  js  c++  java
  • BZOJ 3230:相似子串

    3230: 相似子串

    Time Limit: 20 Sec  Memory Limit: 128 MB
    Submit: 1527  Solved: 371
    [Submit][Status][Discuss]

    Description

    Input

    输入第1行,包含3个整数N,Q。Q代表询问组数。
    第2行是字符串S。
    接下来Q行,每行两个整数i和j。(1≤i≤j)。

    Output

    输出共Q行,每行一个数表示每组询问的答案。如果不存在第i个子串或第j个子串,则输出-1。

    Sample Input

    5 3
    ababa
    3 5
    5 9
    8 10

    Sample Output

    18
    16
    -1

    HINT

    样例解释

    第1组询问:两个子串是“aba”,“ababa”。f = 32 + 32 = 18。

    第2组询问:两个子串是“ababa”,“baba”。f = 02 + 42 = 16。

    第3组询问:不存在第10个子串。输出-1。


    数据范围

    N≤100000,Q≤100000,字符串只由小写字母'a'~'z'组成

    Source

    题解:

    感觉Source里面已经写的很清楚了...

    分别求出正串和反串的后缀数组,然后二分找出第i个和第j个串,查询ij串的最长前缀和最长后缀...

    注意ij可能会超出int,所以记得开longlong...

    代码:

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    //by NeighThorn
    #define int long long
    using namespace std; 
    
    const int maxn=100000+5;
    
    int n,q,gs[maxn],wb[maxn],wv[maxn];
    
    long long sum[maxn];
    
    char s[maxn];
    
    struct M{
    	
    	int sa[maxn],st[maxn][25],ran[maxn],height[maxn];
    	
    	inline void prework(void){
    		memset(sa,0,sizeof(sa));
    		memset(ran,0,sizeof(ran));
    		memset(height,0,sizeof(height));
    	}
    	
    	inline bool cmp(int *x,int a,int b,int l){
    		return x[a]==x[b]&&x[a+l]==x[b+l];
    	}
    	
    	inline void da(int *sa,int *x,int n,int m){
    		int i,j,p,*y=wb;
    		for(i=0;i<m;i++) gs[i]=0;
    		for(i=0;i<n;i++) gs[x[i]]++;
    		for(i=1;i<m;i++) gs[i]+=gs[i-1];
    		for(i=n-1;~i;i--) sa[--gs[x[i]]]=i;
    		for(j=1,p=1;p<n;j<<=1,m=p){
    			for(i=n-j,p=0;i<n;i++) y[p++]=i;
    			for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;
    			for(i=0;i<n;i++) wv[i]=x[y[i]];
    			for(i=0;i<m;i++) gs[i]=0;
    			for(i=0;i<n;i++) gs[wv[i]]++;
    			for(i=1;i<m;i++) gs[i]+=gs[i-1];
    			for(i=n-1;~i;i--) sa[--gs[wv[i]]]=y[i];
    			p=1;swap(x,y);x[sa[0]]=0;
    			for(i=1;i<n;i++) x[sa[i]]=cmp(y,sa[i],sa[i-1],j)?p-1:p++;
    		}
    	}
    	
    	inline void calheight(int n){
    		int i,j,k=0;
    		for(i=0;i<=n;i++) ran[sa[i]]=i;
    		for(i=0;i<n;height[ran[i++]]=k)
    			for(k?k--:233,j=sa[ran[i]-1];s[i+k]==s[j+k];k++);
    	}
    	
    	inline void init(void){
    		for(int i=1;i<=n;i++)
    			st[i][0]=height[i];
    		for(int j=1;j<=20;j++)
    			for(int i=1;i+(1<<j-1)<=n;i++)
    				st[i][j]=min(st[i][j-1],st[i+(1<<j-1)][j-1]);
    	}
    	
    	inline int lcp(int x,int y){
    		if(x==y)
    			return n;
    		x=ran[x],y=ran[y];
    		if(x>y)
    			swap(x,y);
    		x++;
    		int len=y-x+1,k;
    		for(k=20;k>=0;k--)
    			if(len&(1<<k)||k==0)
    				break;
    		return min(st[x][k],st[y-(1<<k)+1][k]);
    	}
    	
    }pre,suf;
    
    inline void find(int x,int *sa,int *height,int *ran,int &be,int &en){
    	int l=1,r=n;
    	while(l<=r){
    		int mid=(l+r)>>1;
    		if(sum[mid]>=x)
    			be=sa[mid],r=mid-1;
    		else
    			l=mid+1;
    	}
    	en=be+height[ran[be]]+x-sum[ran[be]-1]-1;
    }
    
    inline long long solve(int x,int y){
    	if(x>sum[n]||y>sum[n])
    		return -1;
    	int bex,enx,bey,eny;
    	long long ans=0;
    	find(x,pre.sa,pre.height,pre.ran,bex,enx);
    	find(y,pre.sa,pre.height,pre.ran,bey,eny);
    	int lala=min(min(eny-bey+1,enx-bex+1),pre.lcp(bex,bey));
    	ans+=1LL*lala*lala;
    	lala=min(min(eny-bey+1,enx-bex+1),suf.lcp(n-enx-1,n-eny-1));
    	ans+=1LL*lala*lala;
    	return ans;
    }
    
    signed main(void){
    	scanf("%lld%lld%s",&n,&q,s);
    	memset(sum,0,sizeof(sum));
    	pre.prework(),suf.prework();
    	for(int i=0;i<n;i++) pre.ran[i]=s[i],suf.ran[i]=s[n-i-1];
    	pre.da(pre.sa,pre.ran,n+1,1111);
    	memset(wb,0,sizeof(wb));
    	memset(wv,0,sizeof(wv));
    	suf.da(suf.sa,suf.ran,n+1,1111);
    	pre.calheight(n);
    	for(int i=0,j=n-1;i<j;i++,j--)
    		swap(s[i],s[j]); 
    	suf.calheight(n);
    	pre.init(),suf.init();
    	for(int i=1;i<=n;i++)
    		sum[i]=sum[i-1]+n-pre.sa[i]-pre.height[i];
    	for(int i=1,x,y;i<=q;i++)
    		scanf("%lld%lld",&x,&y),printf("%lld
    ",solve(x,y));
    	return 0;
    }
    //1234
    

      


    By NeighThorn

  • 相关阅读:
    PS做图片,如何使背景透明
    C# 在线培训之零基础入门 01:开篇及C#程序、解决方案的结构
    C# 在线培训之零基础入门 02:源码管理之TFS入门
    [ASP.NET] 浅析HtmlForm控件
    Asp.net内置对象之Session
    Asp.net内置对象之Cookies
    [WinForm] 自动补全控件
    ASP.NET内置对象之Request对象
    C#开发Activex控件与JavaScript的互调
    XHTML学习资料(五)—— 表单
  • 原文地址:https://www.cnblogs.com/neighthorn/p/6390428.html
Copyright © 2011-2022 走看看