zoukankan      html  css  js  c++  java
  • 后缀数组之hihocoder 重复旋律1-4

    蒟蒻知道今天才会打后缀数组,而且还是nlogn^2的。。。但基本上还是跑得过的;

    重复旋律1:

    二分答案,把height划分集合,height<mid就重新划分,这样保证了每个集合中的LCP>=mid,套路板子题

    // MADE BY QT666
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<iostream>
    #include<cstring>
    using namespace std;
    typedef long long ll;
    const int N=1000050;
    int gi(){
      int x=0,flag=1;
      char ch=getchar();
      while(ch<'0'||ch>'9'){if(ch=='-') flag=-1;ch=getchar();}
      while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
      return x*flag;
    }
    int sa[N],n,len,y[N],rk,rnk[N],height[N],ans,a[N],k;
    struct data{
      int fir,sec,id;
    }x[N];
    bool cmp(const data &a,const data &b){
      if(a.fir==b.fir) return a.sec<b.sec;
      else return a.fir<b.fir;
    }
    void work2(){
      rk=1;y[x[1].id]=rk;
      for(int i=2;i<=len;i++){
      	if(x[i-1].fir!=x[i].fir||x[i-1].sec!=x[i].sec) rk++;
      	y[x[i].id]=rk;
      }
    }
    void work(){
      sort(x+1,x+1+len,cmp);work2();
      for(int i=1;i<=len;i<<=1){
      	for(int j=1;j+i<=len;j++) x[j].fir=y[j],x[j].sec=y[j+i],x[j].id=j;
    	for(int j=len-i+1;j<=len;j++) x[j].fir=y[j],x[j].sec=0,x[j].id=j;
    	sort(x+1,x+1+len,cmp);work2();
    	if(rk==len) break;
      }
    }
    void get_height(){
    	int kk=0;for(int i=1;i<=len;i++) rnk[sa[i]]=i;
    	for(int i=1;i<=len;i++){
    		if(kk) kk--;
    		int j=sa[rnk[i]-1];
    		while(a[i+kk]==a[j+kk]) kk++;
    		height[rnk[i]]=kk;
    	}
    }
    bool check(int mid){
    	int ret=1,size=1;
    	for(int i=2;i<=len;i++){
    		if(height[i]<mid) ret=max(ret,size),size=1;
    		else size++;
    	}
    	return ret>=k;
    }
    int main(){
      len=gi();k=gi();for(int i=1;i<=len;i++) a[i]=gi();
      for(int i=1;i<=len;i++) x[i].id=i,x[i].fir=x[i].sec=a[i];
      work();for(int i=1;i<=len;i++) sa[y[i]]=i;
      get_height();int l=0,r=len;
      while(l<=r){
      	int mid=(l+r)>>1;
      	if(check(mid)) ans=mid,l=mid+1;
      	else r=mid-1;
      }
      printf("%d
    ",ans);
      return 0;
    }
    

    重复旋律2:

    和上题差不多,二分答案,把height划分集合,维护集合中的最左端和最右端,判断两端相减>=mid;

    // MADE BY QT666
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<iostream>
    #include<cstring>
    using namespace std;
    typedef long long ll;
    const int N=1000050;
    int gi(){
      int x=0,flag=1;
      char ch=getchar();
      while(ch<'0'||ch>'9'){if(ch=='-') flag=-1;ch=getchar();}
      while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
      return x*flag;
    }
    int sa[N],n,len,y[N],rk,rnk[N],height[N],ans,a[N],k;
    struct data{
      int fir,sec,id;
    }x[N];
    bool cmp(const data &a,const data &b){
      if(a.fir==b.fir) return a.sec<b.sec;
      else return a.fir<b.fir;
    }
    void work2(){
      rk=1;y[x[1].id]=rk;
      for(int i=2;i<=len;i++){
      	if(x[i-1].fir!=x[i].fir||x[i-1].sec!=x[i].sec) rk++;
      	y[x[i].id]=rk;
      }
    }
    void work(){
      sort(x+1,x+1+len,cmp);work2();
      for(int i=1;i<=len;i<<=1){
      	for(int j=1;j+i<=len;j++) x[j].fir=y[j],x[j].sec=y[j+i],x[j].id=j;
    	for(int j=len-i+1;j<=len;j++) x[j].fir=y[j],x[j].sec=0,x[j].id=j;
    	sort(x+1,x+1+len,cmp);work2();
    	if(rk==len) break;
      }
    }
    void get_height(){
    	int kk=0;for(int i=1;i<=len;i++) rnk[sa[i]]=i;
    	for(int i=1;i<=len;i++){
    		if(kk) kk--;
    		int j=sa[rnk[i]-1];
    		while(a[i+kk]==a[j+kk]) kk++;
    		height[rnk[i]]=kk;
    	}
    }
    bool check(int mid){
    	int minn=sa[1],maxn=sa[1];
    	for(int i=2;i<=len;i++){
    		if(height[i]<mid){
    			if(maxn-minn>=mid) return 1;
    			minn=maxn=sa[i];
    		}
    		minn=min(minn,sa[i]),maxn=max(maxn,sa[i]);
    	}
    	return 0;
    }
    int main(){
      len=gi();for(int i=1;i<=len;i++) a[i]=gi();
      for(int i=1;i<=len;i++) x[i].id=i,x[i].fir=x[i].sec=a[i];
      work();for(int i=1;i<=len;i++) sa[y[i]]=i;
      get_height();int l=0,r=len;
      while(l<=r){
      	int mid=(l+r)>>1;
      	if(check(mid)) ans=mid,l=mid+1;
      	else r=mid-1;
      }
      printf("%d
    ",ans);
      return 0;
    }
    

    重复旋律3:

    还是板子,把两个串用"#"分开,然后还是二分答案划分height集合

    // MADE BY QT666
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<iostream>
    #include<cstring>
    using namespace std;
    typedef long long ll;
    const int N=1000050;
    int gi(){
      int x=0,flag=1;
      char ch=getchar();
      while(ch<'0'||ch>'9'){if(ch=='-') flag=-1;ch=getchar();}
      while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
      return x*flag;
    }
    int sa[N],n,len,y[N],rk,rnk[N],height[N],ans,cor[N],num[3];
    char ch[N],ch2[N],a[N];
    struct data{
      int fir,sec,id;
    }x[N];
    bool cmp(const data &a,const data &b){
      if(a.fir==b.fir) return a.sec<b.sec;
      else return a.fir<b.fir;
    }
    void work2(){
      rk=1;y[x[1].id]=rk;
      for(int i=2;i<=len;i++){
      	if(x[i-1].fir!=x[i].fir||x[i-1].sec!=x[i].sec) rk++;
      	y[x[i].id]=rk;
      }
    }
    void work(){
      sort(x+1,x+1+len,cmp);work2();
      for(int i=1;i<=len;i<<=1){
      	for(int j=1;j+i<=len;j++) x[j].fir=y[j],x[j].sec=y[j+i],x[j].id=j;
    	for(int j=len-i+1;j<=len;j++) x[j].fir=y[j],x[j].sec=0,x[j].id=j;
    	sort(x+1,x+1+len,cmp);work2();
    	if(rk==len) break;
      }
    }
    void get_height(){
    	int kk=0;for(int i=1;i<=len;i++) rnk[sa[i]]=i;
    	for(int i=1;i<=len;i++){
    		if(kk) kk--;
    		int j=sa[rnk[i]-1];
    		while(a[i+kk]==a[j+kk]) kk++;
    		height[rnk[i]]=kk;
    	}
    }
    bool check(int mid){
    	memset(num,0,sizeof(num));num[cor[sa[1]]]++;
    	for(int i=2;i<=len;i++){
    		if(height[i]<mid){
    			if(num[1]&&num[2]) return 1;
    			memset(num,0,sizeof(num));
    		}
    		num[cor[sa[i]]]++;
    	}
    	return 0;
    }
    int main(){
      scanf("%s",ch+1);scanf("%s",ch2+1);
      int len1=strlen(ch+1),len2=strlen(ch2+1);len=len1+len2+1;
      for(int i=1;i<=len1;i++) a[i]=ch[i],cor[i]=1;a[len1+1]='#';
      for(int i=1;i<=len2;i++) a[len1+1+i]=ch2[i],cor[len1+1+i]=2;
      for(int i=1;i<=len;i++) x[i].id=i,x[i].fir=x[i].sec=a[i]-'a'+1;
      work();for(int i=1;i<=len;i++) sa[y[i]]=i;
      get_height();
      int l=0,r=min(len1,len2);
      while(l<=r){
      	int mid=(l+r)>>1;
      	if(check(mid)) ans=mid,l=mid+1;
      	else r=mid-1;
      }
      printf("%d
    ",ans);
      return 0;
    }
    

      

    重复旋律4:

    真正的大火题。。。

    首先暴力需要枚举长度L,以及串开始的位置i,则以i开始,循环长度为L的答案为1+lcp(i,i+L)/L,记为k(i,L);这个把图画一下还是很好理解的

    优化的话可以只考虑L的整数倍上的位置,然后对于不在整数倍上的x,在他后面的最近的L的整数倍数为p,则k(x,L)不大于k(p,L)+1,

    因为我们知道i和i+L的lcp,那么i+lcp和i+L+lcp是失配的,不然lcp还可以更长,所以在这里就gi了。

    然后因为x和p相差不超过L,所以k的值顶多加1;

    然后假设存在一个x使得k(x,L)==k(p,L)+1,那么x=i-L+lcp%L,这相当把失配位置往前挪(续..)了一个L,可以画图理解一下,所以只需要额外判断k(x,L)即可

    然后

    for(int L=1;L<=len;L++){

       for(int i=L;i+L<=len;i+=L){

       }

    }

    是一个经典的nlogn复杂度,很优秀。。。lcp的话就是height的rmq最小值即可,ST表即可。妙不可言

    // MADE BY QT666
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<iostream>
    #include<cstring>
    using namespace std;
    typedef long long ll;
    const int N=200050;
    int gi(){
      int x=0,flag=1;
      char ch=getchar();
      while(ch<'0'||ch>'9'){if(ch=='-') flag=-1;ch=getchar();}
      while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
      return x*flag;
    }
    int sa[N],len,y[N],rk,rnk[N],height[N],ans,pre[N],pre2[N],ST[N][20];
    char ch[N],ch2[N],a[N];
    struct data{
      int fir,sec,id;
    }x[N];
    bool cmp(const data &a,const data &b){
      if(a.fir==b.fir) return a.sec<b.sec;
      else return a.fir<b.fir;
    }
    void work2(){
      rk=1;y[x[1].id]=rk;
      for(int i=2;i<=len;i++){
        if(x[i-1].fir!=x[i].fir||x[i-1].sec!=x[i].sec) rk++;
        y[x[i].id]=rk;
      }
    }
    void work(){
      sort(x+1,x+1+len,cmp);work2();
      for(int i=1;i<=len;i<<=1){
        for(int j=1;j+i<=len;j++) x[j].fir=y[j],x[j].sec=y[j+i],x[j].id=j;
        for(int j=len-i+1;j<=len;j++) x[j].fir=y[j],x[j].sec=0,x[j].id=j;
        sort(x+1,x+1+len,cmp);work2();
        if(rk==len) break;
      }
    }
    void get_height(){
      int kk=0;for(int i=1;i<=len;i++) rnk[sa[i]]=i;
      for(int i=1;i<=len;i++){
        if(kk) kk--;
        int j=sa[rnk[i]-1];
        while(a[i+kk]==a[j+kk]) kk++;
        height[rnk[i]]=kk;
      }
    }
    void make_ST(){
      pre[0]=1;for(int i=1;i<=16;i++) pre[i]=pre[i-1]<<1;
      pre2[0]=-1;for(int i=1;i<=len;i++) pre2[i]=pre2[i>>1]+1;
      for(int i=2;i<=len;i++) ST[i][0]=height[i];
      for(int j=1;j<=16;j++)
        for(int i=2;i<=len;i++){
          if(i+pre[j]-1<=len){
    	ST[i][j]=min(ST[i][j-1],ST[i+pre[j-1]][j-1]);
          }
        }
    }
    int query(int l,int r){
      int x=pre2[r-l+1];
      return min(ST[l][x],ST[r-pre[x]+1][x]);
    }
    int LCP(int l,int r){
      if(l>r) swap(l,r);
      return query(l+1,r);
    }
    int main(){
      scanf("%s",a+1);len=strlen(a+1);
      for(int i=1;i<=len;i++) x[i].id=i,x[i].fir=x[i].sec=a[i]-'a'+1;
      work();for(int i=1;i<=len;i++) sa[y[i]]=i;
      get_height();make_ST();
      for(int L=1;L<=len;L++){
        for(int i=L;i+L<=len;i+=L){
          int lcp=LCP(rnk[i],rnk[i+L]);ans=max(ans,1+lcp/L);
          ans=max(ans,LCP(rnk[i-L+lcp%L],rnk[i+lcp%L])/L+1);
        }
      }
      printf("%d
    ",ans);
      return 0;
    }
    

      

  • 相关阅读:
    将16进制的颜色值变成UIColor
    验证邮箱地址方法
    iOS 推送通知详解
    在UITextView中添加placeholder
    移除所有子视图removeAllSubviews
    如何书写高质量的jQuery代码
    reset.css
    CSS3笔记
    10个可以直接拿来用的JQuery代码片段
    js定时器
  • 原文地址:https://www.cnblogs.com/qt666/p/7103659.html
Copyright © 2011-2022 走看看