zoukankan      html  css  js  c++  java
  • BZOJ1396: 识别子串

    题解:很裸的后缀数组 利用h函数的特性用线段树维护等差数列即可

    #include <bits/stdc++.h>
    const int MAXN=1e5+10;
    const int inf=1e9+10;
    using namespace std;
    int txt[MAXN],sa[MAXN],t1[MAXN],t2[MAXN],rank1[MAXN],rank2[MAXN],td[MAXN];
    bool cmp(int f[],int e,int w,int k){return f[e]==f[w]&&f[e+k]==f[w+k];}
    void Sa(char s[]){
        int m=550;int len=strlen(s);
        int *rank1=t1;int *td=t2;
        for(int i=0;i<m;i++)txt[i]=0;
        for(int i=0;i<len;i++)rank1[i]=s[i],txt[s[i]]++;
        for(int i=1;i<m;i++)txt[i]+=txt[i-1];
        for(int i=len-1;i>=0;i--)sa[--txt[s[i]]]=i;
        for(int k=1;k<=len;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;
        }
        return ;
    }
    int H[MAXN],h[MAXN];
    void hh(char s[]){
        int len=strlen(s);
        for(int i=0;i<len;i++)rank2[sa[i]]=i;
        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(w<len&&t<len){
    	    if(s[w]==s[t])k++;
    	    else break;
    	    t++;w++;
    	}
    	H[i]=k;h[rank2[i]]=k;
        }
    }
    int flag[MAXN<<2],flag1[MAXN<<2],ans[MAXN];
    void push(int x,int l,int r){
        //flag[x<<1]=min(flag[x<<1],flag[x]);
        //flag[x<<1|1]=min(flag[x<<1|1],flag[x]);
        //flag[x]=inf;
        if(flag[x]!=inf){
    	flag[x<<1]=min(flag[x],flag[x<<1]);
    	flag[x<<1|1]=min(flag[x],flag[x<<1|1]);
    	flag[x]=inf;
        }
        if(flag1[x]!=inf){
    	flag1[x<<1]=min(flag1[x<<1],flag1[x]);
    	int mid=(l+r)>>1;
    	flag1[x<<1|1]=min(flag1[x<<1|1],flag1[x]+(mid+1-l));
    	flag1[x]=inf;
        }
    }
    void built(int rt,int l,int r){
        flag[rt]=inf;flag1[rt]=inf;
        if(l==r)return ;
        int mid=(l+r)>>1;
        built(rt<<1,l,mid);
        built(rt<<1|1,mid+1,r);
    }
    void update1(int rt,int l,int r,int ql,int qr,int vul){
        if(ql<=l&&r<=qr){flag[rt]=min(flag[rt],vul);return ;}
        int mid=(l+r)>>1;
        push(rt,l,r);
        if(ql<=mid)update1(rt<<1,l,mid,ql,qr,vul);
        if(qr>mid)update1(rt<<1|1,mid+1,r,ql,qr,vul);
    }
    int start;
    void update2(int rt,int l,int r,int ql,int qr){
        if(ql<=l&&r<=qr){flag1[rt]=min(flag1[rt],start);start+=(r+1-l);return ;}
        int mid=(l+r)>>1;
        push(rt,l,r);
        if(ql<=mid)update2(rt<<1,l,mid,ql,qr);
        if(qr>mid)update2(rt<<1|1,mid+1,r,ql,qr);
    }
    void querty(int rt,int l,int r){
        if(l==r){ans[l]=min(flag[rt],flag1[rt]);return ;}
        int mid=(l+r)>>1;
        push(rt,l,r);
        querty(rt<<1,l,mid);
        querty(rt<<1|1,mid+1,r);
    }
    char str[MAXN];
    int main(){
        scanf(" %s",str);
        int len=strlen(str);str[len++]='$';
     //   cout<<str<<endl;
        Sa(str);hh(str);
      // for(int i=1;i<len;i++)cout<<h[i]<<" ";
       // cout<<endl;
       // cout<<"SA"<<endl;
       // for(int i=1;i<len;i++)cout<<sa[i]<<" ";
       // cout<<endl;
        //int len=strlen(str);
        h[len]=0;built(1,1,len-1);
        for(int i=1;i<len;i++){
    	int len1=max(h[i],h[i+1]);
    	// i+  //len1+1// i+len1
    //	cout<<len1<<" "<<len<<endl;
    	if(len-sa[i]-1<=len1)continue;
    //	cout<<i<<" "<<len1<<endl;
    	update1(1,1,len-1,sa[i]+1,sa[i]+len1+1,len1+1);
    	start=len1+2;int lx=sa[i]+len1+2;
    	if(lx<len)update2(1,1,len-1,lx,len-1);
        }
        querty(1,1,len-1);
        for(int i=1;i<len;i++){
    	if(ans[i]==inf)printf("%d
    ",len-1);
    	else printf("%d
    ",ans[i]);
        }
        return 0;
    }
    

    1396: 识别子串

    Time Limit: 10 Sec  Memory Limit: 162 MB
    Submit: 602  Solved: 383
    [Submit][Status][Discuss]

    Description

    Input

    一行,一个由小写字母组成的字符串S,长度不超过10^5

    Output

    L行,每行一个整数,第i行的数据表示关于S的第i个元素的最短识别子串有多长.

    Sample Input

    agoodcookcooksgoodfood

    Sample Output

    1
    2
    3
    3
    2
    2
    3
    3
    2
    2
    3
    3
    2
    1
    2
    3
    3
    2
    1
    2
    3
    4

  • 相关阅读:
    数组添加元素到特定位置
    jquery $().each,$.each的区别
    JSON字符串 与 JSON对象 互转
    js 获取 url 参数
    js 获取随机数 Math.random()
    js中的|| 与 &&
    js立即执行函数
    css 蒙层
    css 多行文本的溢出显示省略号(移动端)
    移动端利用-webkit-box水平垂直居中(旧弹性盒)
  • 原文地址:https://www.cnblogs.com/wang9897/p/9158040.html
Copyright © 2011-2022 走看看