• bzoj 4310 跳蚤


    后缀数组+二分

    1.

    从后往前贪心扫

    当必须分的时候就分一段

    注意比较两个串大小时的细节

    2.

    先二分这个串第一次出现时在后缀数组上的位置

    再二分具体是哪个串

    从前往后扫,使右端点不断往左缩,当 右<=左 时分一段

    快的飞起

    1.

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define N 200005
    #define ll long long
    using namespace std;
    char s[N];
    int rk[N],sa[N],wb[N],sum[N];
    void sasa(int n,int m)
    {
    	int *x=rk,*y=wb;
    	for(int i=0;i<m;i++)sum[i]=0;
    	for(int i=0;i<n;i++)sum[x[i]=s[i]]++;
    	for(int i=1;i<m;i++)sum[i]+=sum[i-1];
    	for(int i=n-1;i>=0;i--)sa[--sum[x[i]]]=i;
    	for(int j=1,p=1;p<n;m=p,j<<=1)
    	{
    		p=0;
    		for(int i=n-j;i<n;i++)y[p++]=i;
    		for(int i=0;i<n;i++)if(sa[i]>=j)y[p++]=sa[i]-j;
    		for(int i=0;i<m;i++)sum[i]=0;
    		for(int i=0;i<n;i++)sum[x[i]]++;
    		for(int i=1;i<m;i++)sum[i]+=sum[i-1];
    		for(int i=n-1;i>0;i--)sa[--sum[x[y[i]]]]=y[i];
    		swap(x,y);x[sa[0]]=0;p=1;
    		for(int i=1;i<n;i++)
    			x[sa[i]]=y[sa[i]]==y[sa[i-1]]&&y[sa[i]+j]==y[sa[i-1]+j]?p-1:p++;
    	}
    	return ;
    }
    int h[N];
    void calh(int n)
    {
    	for(int i=1;i<=n;i++)rk[sa[i]]=i;
    	int k=0;
    	for(int i=0;i<n;i++)
    	{
    		if(k)k--;
    		int j=sa[rk[i]-1];
    		while(s[j+k]==s[i+k])k++;
    		h[rk[i]]=k;
    	}
    	return ;
    }
    int mn[N][20],lg[N],n;
    void ST()
    {
    	lg[0]=-1;
    	for(int i=1;i<=100000;i++)lg[i]=lg[i>>1]+1;
    	for(int i=1;i<=n;i++)mn[i][0]=h[i];
    	for(int i=1;i<20;i++)
    	{
    		for(int j=1;j<=n;j++)
    		{
    			if(j+(1<<(i-1))<=n)
    			{
    				mn[j][i]=min(mn[j][i-1],mn[j+(1<<(i-1))][i-1]);
    			}
    			else mn[j][i]=mn[j][i-1];
    		}
    	}return ;
    }
    int qur(int l,int r)
    {
    	int k=lg[r-l+1];
    	return min(mn[l][k],mn[r-(1<<k)+1][k]);
    }
    bool cmp(int x,int len1,int y,int len2)
    {
    	if(x<y)
    	{
    		int p=qur(x+1,y);
    		if(p>=len2&&p<len1)return 0;
    		return 1;
    	}
    	else if(x>y)
    	{
    		int p=qur(y+1,x);
    		if(p>=len1)return 1;
    		return 0;
    	}
    	else
    	{
    		if(len1<=len2)return 1;
    		return 0;
    	}
    }
    int k;
    bool pan(ll x)
    {
    	int now=1;ll tot=0;
    	int pos,len;
    	for(int i=1;i<=n;i++)
    	{
    		ll pre=tot;
    		tot+=n-sa[i]-h[i];
    		if(tot>=x)
    		{
    			pos=i;len=h[i]+x-pre;
    			break;
    		}
    	}
    	int ta=n-1;
    	for(int i=n-1;i>=0;i--)
    	{
    		if(!cmp(rk[i],1,pos,len))return 0;
    		if(!cmp(rk[i],ta-i+1,pos,len))
    		{
    			ta=i,now++;
    		}
    	}
    	return now<=k;
    }
    int main()
    {
    	scanf("%d",&k);
    	scanf("%s",s);
    	n=strlen(s);
    	sasa(n+1,256);
    	calh(n);
    	ST();
    	ll sm=1LL*n*(n+1)/2;
    	for(int i=1;i<=n;i++)sm-=h[i];
    	ll l=1,r=sm;
    	while(l<r)
    	{
    		ll mid=(l+r)>>1;
    		if(pan(mid))r=mid;
    		else l=mid+1;
    	}
    	ll tot=0;
    	int pos,len;
    	for(int i=1;i<=n;i++)
    	{
    		ll pre=tot;
    		tot+=n-sa[i]-h[i];
    		if(tot>=l)
    		{
    			pos=i;len=h[i]+l-pre;
    			break;
    		}
    	}
    	for(int i=0;i<len;i++)
    	{
    		putchar(s[sa[pos]+i]);
    	}puts("");
    	return 0;
    }
    

    2.

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define N 200005
    using namespace std;
    char s[N];
    int c[N],sa[N],m,n,rk[N],t1[N],t2[N],v[N];
    void saa(char *s,int n,int m)
    {
        int *x=t1,*y=t2;
        for(int i=0;i<m;i++)c[i]=0;
        for(int i=0;i<n;i++)c[x[i]=s[i]]++;
        for(int i=1;i<m;i++)c[i]+=c[i-1];
        for(int i=0;i<n;i++)sa[--c[x[i]]]=i;
        int p=1;
        for(int j=1;p<n;j<<=1,m=p)
        {
            p=0;
            for(int i=n-j;i<n;i++)y[p++]=i;
            for(int i=0;i<n;i++)if(sa[i]>=j)y[p++]=sa[i]-j;
            for(int j=0;j<m;j++)c[j]=0;
            for(int i=0;i<n;i++)c[x[i]]++;
            for(int j=1;j<m;j++)c[j]+=c[j-1];
            for(int i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i];
            swap(x,y);x[sa[0]]=0;p=1;
            for(int i=1;i<n;i++)
              x[sa[i]]=y[sa[i]]==y[sa[i-1]]&&y[sa[i]+j]==y[sa[i-1]+j]?p-1:p++;
        }
        return ;
    }
    int h[N];
    void calh(int n)
    {
        for(int i=1;i<=n;i++)rk[sa[i]]=i;
        int k=0;
        for(int i=0;i<n;i++)
        {
            if(k)k--;
            int j=sa[rk[i]-1];
            while(s[i+k]==s[j+k])k++;
            h[rk[i]]=k;
        }
        return ;
    }
    int main()
    {
        scanf("%d %s",&m,s);
        n=strlen(s);s[n]=0;
        saa(s,n+1,300);
        calh(n);
        int l=1,r=n;
        while(l<r)
        {
            int mid=(l+r)>>1,num=0,mn=n,m1=n;
            for(int i=mid+1;i<=n;i++){m1=min(m1,h[i]);v[sa[i]]=m1;if(!h[i])num=m+1;}
            for(int i=0;i<=n-1;i++)
            {
                if(mn==i)num++,mn=n;
                if(v[i])mn=min(mn,i+v[i]);
            }
            if(num+1<=m)r=mid;else l=mid+1;
            for(int i=mid+1;i<=n;i++)v[sa[i]]=0; 
        }
        int u=l;
        l=h[u]+1,r=n-sa[u];     
        while(l<r)
        {
             int mid=(l+r)>>1,k=u,num=0,mn=n,m1=mid;
             for(int i=u+1;i<=n;i++){m1=min(m1,h[i]);v[sa[i]]=m1;}
             v[sa[u]]=mid;
             for(int i=0;i<n;i++)
             {
                if(mn==i)num++,mn=n;
                if(v[i])mn=min(mn,i+v[i]);
             }
             if(num+1<=m)r=mid;else l=mid+1;
             for(int i=k;i<=u;i++)v[sa[i]]=0;
        }
        for(int i=1;i<=l;i++)printf("%c",s[sa[u]+i-1]);
        puts("");
        return 0;
    }
    

      

  • 相关阅读:
    TH-Union教学机 指令总结
    Manjaro 显卡驱动安装
    grub学习内容
    manjaro 折腾
    链栈的实现
    汇编综合实验
    二叉树
    Oracle表空间基本操作
    Windows7/10实现ICMP(ping命令)
    WireShark——IP协议包分析(Ping分析IP协议包)
  • 原文地址:https://www.cnblogs.com/ezyzy/p/6737036.html
Copyright © 2020-2023  润新知