zoukankan      html  css  js  c++  java
  • BZOJ4310 跳蚤

    Link
    先求SA,并求出本质不同的子串数目。
    然后二分答案(mid),并求出排名为(mid)的子串(t)
    检验从后往前贪心,尽可能地让最后一个(suf)更长。

    #include<cstdio>
    #include<numeric>
    #include<cstring>
    #include<algorithm>
    typedef long long i64;
    const int N=100007;
    char str[N+10];
    int n,k,sa[N],rank[N],h[N],s[N<<1],t[N<<1],pos[N<<1],r[N>>1],c[N>>1],f[16][N],g[N],Log[N];
    i64 L,R;int ansl,ansr,nowl,nowr,len;
    #define is(x,a) sa[r[s[x]]a]=x
    #define IS(S)								
        memset(sa+1,0,n<<2),memset(c+1,0,m<<2);				
        for(int i=1;i<=n;++c[s[i++]]);					
        std::partial_sum(c+1,c+m+1,c+1),memcpy(r+1,c+1,m<<2);		
        for(int i=N;i;--i) is(S[i],--);					
        for(int i=1;i<=m;++i) r[i]=c[i-1]+1;				
        for(int i=1;i<=n;++i) if(sa[i]>1&&t[sa[i]-1]) is(sa[i]-1,++);	
        memcpy(r+1,c+1,m<<2);						
        for(int i=n;i;--i) if(sa[i]>1&&!t[sa[i]-1]) is(sa[i]-1,--);
    void SAIS(int n,int m,int*s,int*t,int*pos)
    {
        int N=0,M=rank[1]=0,*S=s+n;
        t[n]=0;
        for(int i=n-1;i;--i) t[i]=s[i]^s[i+1]? s[i]>s[i+1]:t[i+1];
        for(int i=2;i<=n;++i) rank[i]=t[i-1]&&!t[i]? pos[++N]=i,N:0;
        IS(pos);
        for(int i=1,x,y=0;i<=n;++i)
    	if((x=rank[sa[i]]))
    	{
    	    if(M<=1||pos[x+1]-pos[x]!=pos[y+1]-pos[y]) ++M;
    	    else for(int a=pos[x],b=pos[y];a<=pos[x+1];++a,++b) if((s[a]<<1|t[a])^(s[b]<<1|t[b])) {++M;break;}
    	    S[y=x]=M;
    	}
        if(M^N) SAIS(N,M,S,t+n,pos+n); else for(int i=1;i<=N;++i) sa[S[i]]=i;
        for(int i=1;i<=N;++i) S[i]=pos[sa[i]];
        IS(S);
    }
    int lcp(int x,int y){if(x==y) return n-x;x=rank[x],y=rank[y];if(x>y) std::swap(x,y);int k=Log[y-x];return std::min(f[k][x+1],f[k][y-(1<<k)+1]);}
    void work(i64 lim)
    {
        i64 s=0;
        for(int i=1;i<=n;s+=n+1-sa[i]-h[i],++i) if(s+n+1-sa[i]-h[i]>=lim) return nowl=sa[i],nowr=nowl+h[i]+lim-s-1,len=nowr-nowl+1,void();
    }
    int ask(int l,int r)
    {
        int t=std::min(lcp(l,nowl),std::min(r-l+1,len));
        if(t==r-l+1&&t<=len) return 1;
        if(t==len) return 0;
        return str[l+t]<=str[nowl+t];
    }
    int check()
    {
        int c=0;
        for(int i=n,j;i;i=j,++c)
        {
    	for(j=i;j;--j) if(!ask(j,i)) break;
    	if(j==i) return 0;
        }
        return c<=k;
    }
    int main()
    {
        scanf("%d%s",&k,str+1),n=strlen(str+1),R=1ll*n*(n+1)/2;
        for(int i=1;i<=n;++i) s[i]=str[i]-'a'+2;
        s[++n]=1,SAIS(n--,27,s,t,pos);
        for(int i=1;i<=n;++i) rank[sa[i]=sa[i+1]]=i;
        for(int i=1,j,l=0;i<=n;h[rank[i++]]=l) for(j=sa[~-rank[i]],l-=l>0;i+l<=n&&j+l<=n&&s[i+l]==s[j+l];++l);
        for(int i=2;i<=n;++i) Log[i]=Log[i>>1]+1;
        for(int i=1;i<=n;++i) f[0][i]=h[i];
        for(int j=1;j<17;++j) for(int i=1,d=1<<(j-1);i+d<=n;++i) f[j][i]=std::min(f[j-1][i],f[j-1][i+d]);
        for(int i=2;i<=n;++i) R-=h[i];
        for(i64 mid;L<=R;) work(mid=(L+R)>>1),check()? ansl=nowl,ansr=nowr,R=mid-1:L=mid+1;
        for(int i=ansl;i<=ansr;++i) putchar(str[i]);
    }
    
  • 相关阅读:
    中国移动校园WLAN客户端及使用方法
    Win7 开启upnp服务,直接在网络中设置连接路由设备
    转载:迷你云 – 搭建自己的本地多人团队Dropbox 服务
    JLINK V8固件烧录指导
    实验室网站试运营期间的信息管理
    并非如你想象的那般强大,带你重新认识3D打印
    转:技术宅逆天了!如何从按键音中听出周鸿祎的手机号码
    南大学生破译周鸿祎电话获得互联网大佬青睐
    E430 加装固态硬盘(SSD)参考
    iptables_cacti_nagios
  • 原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12312838.html
Copyright © 2011-2022 走看看