zoukankan      html  css  js  c++  java
  • 【后缀数组】poj3581 Sequence

    考虑第一次切割,必然切割的是翻转后字典序最小的前缀,伪证:

    若切割位置更靠前:则会导致第一个数翻转后更靠前,字典序必然更大。

    若切割位置更靠后,则显然也会导致字典序更大。

    ↑,sa即可

    对于第二次切割,有结论:将序列分割成两段再分别翻转得到的序列,可以看作是将两个原序列拼接得到的新序列中的某个字串翻转得到的序列。

    因此计算新序列的sa,再从中选取字典序最小的合适的后缀即可。

    因为要基数排序而又没有告诉权值的范围,因此要离散化。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define N 400001
    struct Point{int p,v;}T[N];
    bool operator < (Point a,Point b){return a.v<b.v;}
    int s[N],n,rev[N],ma[N],zy;
    int t[N],t2[N],sa[N],tong[N];
    bool cmp(int *y,int i,int k)
    {
    	return ((y[sa[i-1]]==y[sa[i]])&&((sa[i-1]+k>=n?-1:y[sa[i-1]+k])==(sa[i]+k>=n?-1:y[sa[i]+k])));
    }
    void build_sa(int s[],int range,int n)
    {
    	int *x=t,*y=t2;
    	memset(tong,0,sizeof(int)*range);
    	for(int i=0;i<n;++i) tong[x[i]=s[i]]++;
    	for(int i=1;i<range;++i) tong[i]+=tong[i-1];
    	for(int i=n-1;i>=0;--i) sa[--tong[x[i]]]=i;
    	for(int k=1;k<=n;k<<=1)
    	  {
    	  	int p=0;
    	  	for(int i=n-k;i<n;++i) y[p++]=i;
    	  	for(int i=0;i<n;++i) if(sa[i]>=k) y[p++]=sa[i]-k;
    	  	memset(tong,0,sizeof(int)*range);
    	  	for(int i=0;i<n;++i) tong[x[y[i]]]++;
    	  	for(int i=1;i<range;++i) tong[i]+=tong[i-1];
    	  	for(int i=n-1;i>=0;--i) sa[--tong[x[y[i]]]]=y[i];
    	  	swap(x,y); p=1; x[sa[0]]=0;
    	  	for(int i=1;i<n;++i) x[sa[i]]=cmp(y,i,k)?p-1:p++;
    	  	if(p>=n) break;
    	  	range=p;
    	  }
    }
    int main()
    {
    	scanf("%d",&n);
    	for(int i=0;i<n;++i)
    	  {
    	  	scanf("%d",&T[i].v);
    	  	T[i].p=i;
    	  }
    	sort(T,T+n);
    	ma[zy++]=T[0].v;
    	for(int i=1;i<n;++i)
    	  {
    	  	if(T[i].v!=T[i-1].v) ++zy;
    	  	s[T[i].p]=zy-1;
    	  	ma[zy-1]=T[i].v;
    	  }
    	reverse_copy(s,s+n,rev);
    	build_sa(rev,zy,n);
    	int p1;
    	for(int i=0;i<n;++i)
    	  {
    	  	p1=n-sa[i];//第一段长度
    	  	if(sa[i]>=2)
    	  	  {
    	  	  	for(int j=sa[i];j<n;++j)
    			  printf("%d
    ",ma[rev[j]]);
    	  	  	break;
    	  	  }
    	  }
    	int n2=n-p1;
    	reverse_copy(s+p1,s+n,rev);
    	memcpy(rev+n2,rev,sizeof(int)*n2);
    	build_sa(rev,zy,n2<<1);
    	for(int i=0;i<(n2<<1);++i)
    	  if(sa[i]&&sa[i]<n2)
    	    {
    	      for(int j=sa[i];j<sa[i]+n2;++j)
    		    printf("%d
    ",ma[rev[j]]);
    	      break;
    	    }
    	return 0;
    }
  • 相关阅读:
    《Linux设备驱动开发详解(第2版)》配套视频登录51cto教育频道
    异常Address already in use: JVM_Bind的处理
    你的Jsp页面有黄×么,有黄色问号么?Multiple annotations found at this line:
    dispatch_get_current_queue 废弃
    二叉树代码(较全)
    ArrayList and LinkedList
    android的tabhost+RadioGroup+PopupWindow
    子进程继承父进程的当前工作目录的问题
    oracle AWR深入研究分析,如何使用
    Linux下对后台进程通过kill传递信号不起作用的问题
  • 原文地址:https://www.cnblogs.com/autsky-jadek/p/4459660.html
Copyright © 2011-2022 走看看