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

    题解:后缀数组的特性我们可以通过对于这个位置比较前一个位置的h值来解决以i位置为起点的后缀能产生多少个和前面的串不同的子串 所以问题转化为 求第k大出现的位置 二分找就ok 然后找出来的位置求一下lcp 然后反过来再求一下就ok

    #include <bits/stdc++.h>
    #define ll long long
    const int MAXN=1e5+10;
    using namespace std;
    char s1[MAXN],s2[MAXN];
    int txt[MAXN],sa[MAXN],td[MAXN],rank1[MAXN],rank2[MAXN],t1[MAXN],t2[MAXN];
    int dp[MAXN][21];int mu[21];int ma[MAXN];
    bool cmp(int f[],int t,int w,int k){return f[t]==f[w]&&f[t+k]==f[w+k];}
    ll ans[MAXN];
    void Sa(char str[]){
      //  cout<<str<<endl;
        int len=strlen(str);int m=128;
        int *td=t1;int *rank1=t2;
        for(int i=0;i<m;i++)txt[i]=0;
        for(int i=0;i<len;i++)rank1[i]=str[i],txt[str[i]]++;
        for(int i=1;i<m;i++)txt[i]+=txt[i-1];
        for(int i=len-1;i>=0;i--)sa[--txt[str[i]]]=i;
        for(int k=1;k<=len;k=k*2){
    	int p=0;
    	for(int i=len-k;i<len;i++)td[p++]=i;
    	for(int i=0;i<len;i++)if(sa[i]>=k)td[p++]=sa[i]-k;
    	for(int i=0;i<m;i++)txt[i]=0;
    	for(int i=0;i<len;i++)txt[rank1[i]]++;
    	for(int i=1;i<m;i++)txt[i]+=txt[i-1];
    	for(int i=len-1;i>=0;i--)sa[--txt[rank1[td[i]]]]=td[i];
    	swap(rank1,td);rank1[sa[0]]=0;p=1;
    	for(int i=1;i<len;i++)rank1[sa[i]]=cmp(td,sa[i],sa[i-1],k)?p-1:p++;
    	if(p==len)return ;
    	m=p;
        }
    }
    int h[MAXN],H[MAXN];ll sum[MAXN];
    void hh(char str[]){
        int len=strlen(str);
        for(int i=0;i<len;i++)rank2[sa[i]]=i;
        memset(h,0,sizeof(h));
        memset(H,0,sizeof(H));
        for(int i=0;i<len;i++){
    	if(rank2[i]==0)continue;
    	int t=sa[rank2[i]-1];int w=i;int k;
    	if(i==0||H[i-1]<=1)k=0;
    	else k=H[i-1]-1,t+=k,w+=k;
    	while(t<len&&w<len){
    	    if(str[t]==str[w])k++;
    	    else break;
    	    t++;w++;
    	}
    	H[i]=k;h[rank2[i]]=k;
        }
    }
    void st(int len){
        for(int i=1;i<len;i++)dp[i][0]=h[i];
        for(int j=1;mu[j]<=len;j++){
    	for(int i=1;i+mu[j]<=len;i++){
    	    dp[i][j]=min(dp[i][j-1],dp[i+mu[j-1]][j-1]);
    	}
        }
    }
    int rmq(int l,int r){
        if(l>r)return MAXN;
        int k=ma[r-l+1];
        return min(dp[l][k],dp[r-mu[k]+1][k]);
    }
    typedef struct node{
        ll l,r;int lx,rx,ly,ry;
    }node;
    node que[MAXN];
    int q;
    int check(ll k,int len){
        int l=1;int r=len-1;
        while(l<=r){
    	int mid=(l+r)>>1;
    	if(sum[mid-1]<k&&sum[mid]>=k)return mid;
    	else if(sum[mid-1]>=k)r=mid-1;
    	else l=mid+1;
        }
        return len;
    }
    void slove(){
        Sa(s1);hh(s1);int len=strlen(s1);st(len);
      //  cout<<s1<<" "<<endl;
     //   for(int i=1;i<len;i++)cout<<sa[i]<<" ";
      //  cout<<endl;
        for(int i=1;i<len;i++){sum[i]=len-1-sa[i]-h[i];}
        //for(int i=1;i<len;i++)cout<<sum[i]<<" ";
        //cout<<endl;
        for(int i=1;i<len;i++)sum[i]+=sum[i-1];
        for(int i=1;i<=q;i++){
    //	cout<<que[i].l<<" "<<que[i].r<<endl;
    	que[i].lx=check(que[i].l,len);que[i].ly=check(que[i].r,len);
    //	cout<<i<<" "<<que[i].lx<<" "<<que[i].ly<<endl;
    	if(que[i].lx>=len||que[i].ly>=len){
    	    ans[i]=-1;continue;
    	}
    	que[i].rx=que[i].l-sum[que[i].lx-1]+h[que[i].lx];que[i].ry=que[i].r-sum[que[i].ly-1]+h[que[i].ly];
    //	cout<<que[i].rx<<"----"<<que[i].ry<<endl;
    	ll k1=min(que[i].rx,min(rmq(que[i].lx+1,que[i].ly),que[i].ry));
    //	cout<<k1<<" "<<endl;
    	ans[i]+=1ll*k1*k1;
    	que[i].rx=(que[i].rx-1)+sa[que[i].lx];
    	que[i].lx=que[i].rx-sa[que[i].lx]+1;
    	que[i].rx=len-2-que[i].rx;
    	que[i].ry=(que[i].ry-1)+sa[que[i].ly];
    	que[i].ly=que[i].ry-sa[que[i].ly]+1;
    	que[i].ry=len-2-que[i].ry;
    //	cout<<que[i].lx<<" "<<que[i].ly<<" "<<que[i].rx<<" "<<que[i].ry<<endl;
        }
    }
    void slove2(){
        Sa(s2);hh(s2);int len=strlen(s2);st(len);
        for(int i=1;i<=q;i++){
    	if(ans[i]==-1)continue;
    	int l=rank2[que[i].rx];int r=rank2[que[i].ry];
    	if(l>r)swap(l,r);l++;
    	ll k1=1ll*min(que[i].lx,min(que[i].ly,rmq(l,r)));
    	ans[i]+=1ll*k1*k1;
        }
    }
    int main(){
        mu[0]=1;for(int i=1;i<=20;i++)mu[i]=mu[i-1]<<1;
        ma[0]=-1;for(int i=1;i<MAXN;i++)if((i&(i-1))==0)ma[i]=ma[i-1]+1;else ma[i]=ma[i-1];
        int n;scanf("%d%d",&n,&q);
        scanf(" %s",s1);int len=strlen(s1);s1[len++]='$';
        for(int i=0;i<len-1;i++)s2[i]=s1[len-i-2];s2[len-1]='$';
    //    cout<<s2<<endl;
        for(int i=1;i<=q;i++)scanf("%lld%lld",&que[i].l,&que[i].r);
        slove();slove2();
        for(int i=1;i<=q;i++)printf("%lld
    ",ans[i]);
    }
    

    3230: 相似子串

    Time Limit: 20 Sec  Memory Limit: 128 MB
    Submit: 1980  Solved: 515
    [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'组成

  • 相关阅读:
    书决战.NET——ASP.NET AJAX与Silverlight实战手册(含光的评论
    C#和.NET 3.0第一步——适用Visual Studio 2005与Visual Studio 这本书怎么样
    Visual Basic.NET 2008控件使用范例详解这本书怎么样
    书C#2005 &.NET 3.0高级编程(第5版)(上、下卷)的评论
    关于Visual J#.NET应用程序设计(高等学校计算机科学与技术教材)的读后感
    Dos命令
    调整markdown 图片大小和对齐方式
    Intellij IDEA设置自定义类描述信息
    Markdown基本语法
    计算机的发展史(待补充)
  • 原文地址:https://www.cnblogs.com/wang9897/p/9212721.html
Copyright © 2011-2022 走看看