后缀数组 (hihocoder重复旋律系列)

重复旋律1

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#define RG register
#define IL inline
#define pi acos(-1.0)
#define ll long long
using namespace std;

int gi() {
  char ch=getchar(); int x=0;
  while(ch<'0' || ch>'9') ch=getchar();
  while(ch>='0' && ch<='9') {x=10*x+ch-'0';ch=getchar();}
  return x;
}

const int maxn = 20010;

int n,ck,inf=1<<30,ans;
int t1[maxn],t2[maxn],c[maxn],s[maxn],sa[maxn];
int ra[maxn],he[maxn];
int q[maxn];

void get_sa(int m) {
  int i,*x=t1,*y=t2;
  for(i=0; i<m; i++) c[i]=0;
  for(i=0; i<n; i++) c[x[i]=s[i]]++;
  for(i=1; i<m; i++) c[i]+=c[i-1];
  for(i=n-1; i>=0; i--) sa[--c[x[i]]]=i;
  for(int k=1; k<=n; k<<=1) {
    int p=0;
    for(i=n-k; i<n; i++) y[p++]=i;
    for(i=0; i<n; i++) if(sa[i]>=k) y[p++]=sa[i]-k;
    for(i=0; i<m; i++) c[i]=0;
    for(i=0; i<n; i++) c[x[y[i]]]++;
    for(i=1; i<m; i++) c[i]+=c[i-1];
    for(i=n-1; i>=0; i--) sa[--c[x[y[i]]]]=y[i];//这时的sa是以第二关键字的排名的排列的
    swap(x,y);//把x数组赋给y数组
    p=1,x[sa[0]]=0;
    for(i=1; i<n; i++)  
      x[sa[i]]=y[sa[i-1]]==y[sa[i]] && y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
    if(p>=n) break;
    m=p;
  }
}

void get_he() {
  int i,j,k=0;
  for(i=0; i<=n; i++) ra[sa[i]]=i;
  for(i=0; i<n; i++) {
    if(k) k--;
    j=sa[ra[i]-1];//rank[n]=0,不会出现负下标
    while(s[i+k] == s[j+k]) k++;
    he[ra[i]]=k;
  }
}

int cal() {//单调队列O(n)维护最小值(单增队列)
  int hd=1,ta=0,res=0;
  for(int i=1; i<ck; i++) {
    while(hd<=ta && he[i]<he[q[ta]]) ta--;
    q[++ta]=i;
  }//先将队列扩展到[1,k-1]
  for(int i=ck; i<=n; i++) {//每次逐次往后移动一个1格,求[i-k+1,i]的最值,即为队头
    while(hd<=ta && he[i]<he[q[ta]]) ta--;
    q[++ta]=i;
    while(hd<=ta && q[hd]<=i-ck+1) hd++;
    res=max(res,he[q[hd]]);
  }
  return res;
}

/*
  要点:
  1'先扩展到k-1
  2'维持单调
  3'区间求最值
*/

int main() {
  n=gi(),ck=gi();
  for(int i=0; i<n; i++) s[i]=gi();
  n++;
  get_sa(100);
  n--;
  get_he();
  int ans=cal();
  printf("%d", ans);
  return 0;
}

重复旋律2

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#define RG register
#define IL inline
#define pi acos(-1.0)
#define ll long long 
using namespace std;

int gi() {
  char ch=getchar(); int x=0;
  while(ch<'0' || ch>'9') ch=getchar();
  while(ch>='0' && ch<='9') {x=10*x+ch-'0';ch=getchar();}
  return x;
}

const int maxn = 100010;

int n,m=1000,ans;
int s[maxn],t1[maxn],t2[maxn],c[maxn];
int sa[maxn],he[maxn],ra[maxn];

void get_sa() {
  int i,*x=t1,*y=t2;
  for(i=0; i<m; i++) c[i]=0;
  for(i=0; i<n; i++) c[x[i]=s[i]]++;
  for(i=1; i<m; i++) c[i]+=c[i-1];
  for(i=n-1; i>=0; i--) sa[--c[x[i]]]=i;
  for(int k=1; k<=n; k<<=1) {
    int p=0;
    for(i=n-k; i<n; i++) y[p++]=i;
    for(i=0; i<n; i++)  if(sa[i]>=k) y[p++]=sa[i]-k;
    for(i=0; i<m; i++) c[i]=0;
    for(i=0; i<n; i++) c[x[y[i]]]++;
    for(i=1; i<m; i++) c[i]+=c[i-1];
    for(i=n-1; i>=0; i--) sa[--c[x[y[i]]]]=y[i];
    swap(x,y);
    p=1,x[sa[0]]=0;
    for(i=1; i<n; i++)
      x[sa[i]]=y[sa[i-1]]==y[sa[i]] && y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
    if(p>=n) break;
    m=p;
  }
}

void get_he() {
  int i,j,k=0;
  for(i=1; i<=n; i++) ra[sa[i]]=i;
  for(i=0; i<n; i++) {
    if(k) k--;
    j=sa[ra[i]-1];//排名在i前面的字符下标j 
    while(s[i+k]==s[j+k]) k++;
    he[ra[i]]=k;
  }
}

bool check(int k) {
  int minsa=1<<30,maxsa=0;
  for(int i=1; i<=n; i++) {
    if(he[i]<k) {
      maxsa=sa[i];
      minsa=sa[i];
    }
    else {
      maxsa=max(sa[i],maxsa);
      minsa=min(sa[i],minsa);
      if(maxsa-minsa>=k) return true;
    }
  }
  return false;
}

int main() {
  n=gi();
  for(int i=0; i<n; i++) s[i]=gi();
  m++,n++,get_sa(),n--;
  get_he();
  int l=0,r=n,mid;
  while(l<=r) {
    mid=(l+r)>>1;
    if(check(mid)) ans=max(ans,mid),l=mid+1;
    else r=mid-1;
  }
  printf("%d", ans);
  return 0;
}

重复旋律3

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#define RG register
#define IL inline
#define pi acos(-1.0)
#define ll long long 
using namespace std;

int gi() {
  char ch=getchar(); int x=0;
  while(ch<'0' || ch>'9') ch=getchar();
  while(ch>='0' && ch<='9') {x=10*x+ch-'0';ch=getchar();}
  return x;
}

const int maxn = 100100;

int n,m=101,ls1,ls2;
char s1[maxn],s2[maxn];
int s[maxn*2],c[maxn*3],t1[maxn*2],t2[maxn*2];
int sa[maxn*2],ra[maxn*2],he[maxn*2];

void get_sa() {
  int i,*x=t1,*y=t2;
  for(i=0; i<m; i++) c[i]=0;
  for(i=0; i<n; i++) c[x[i]=s[i]]++;
  for(i=1; i<m; i++) c[i]+=c[i-1];
  for(i=n-1; i>=0; i--) sa[--c[x[i]]]=i;
  for(int k=1; k<=n; k<<=1) {
    int p=0;
    for(i=n-k; i<n; i++) y[p++]=i;
    for(i=0; i<n; i++) if(sa[i]>=k) y[p++]=sa[i]-k;
    for(i=0; i<m; i++) c[i]=0;
    for(i=0; i<n; i++) c[x[y[i]]]++;
    for(i=1; i<=m; i++) c[i]+=c[i-1];
    for(i=n-1; i>=0; i--) sa[--c[x[y[i]]]]=y[i];
    swap(x,y);
    p=1,x[sa[0]]=0; 
    for(i=1; i<n; i++)
      x[sa[i]]=y[sa[i-1]]==y[sa[i]] && y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
    if(p>=n) break;
    m=p;
  }
}

void get_he() {
  int i,j,k=0;
  for(i=0; i<=n; i++) ra[sa[i]]=i;
  for(i=0; i<n; i++) {
    if(k) k--;
    j=sa[ra[i]-1];
    while(s[j+k]==s[i+k]) k++;
    he[ra[i]]=k;
  }
}

int solve() {
  int ans=0;
  for(int i=1; i<=n; i++) {
    if((sa[i]<ls1 && sa[i-1]>ls1) || (sa[i]>ls1 && sa[i-1]<ls1)) {
      ans=max(ans,he[i]);
    } 
  }
  return ans;
}

int main() {
  scanf("%s%s", s1,s2);
  ls1=strlen(s1),ls2=strlen(s2);
  for(int i=0; i<ls1; i++) s[i]=s1[i]-'a'+1;
  s[ls1]=100;
  for(int i=1; i<=ls2; i++)
    s[i+ls1]=s2[i-1]-'a'+1;
  n=ls1+ls2+1;
  n++;
  get_sa();
  n--;
  get_he();
  printf("%d", solve());
  return 0;
}

重复旋律4

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#define RG register
#define IL inline
#define pi acos(-1.0)
#define ll long long 
using namespace std;

int gi() {
  char ch=getchar(); int x=0;
  while(ch<'0' || ch>'9') ch=getchar();
  while(ch>='0' && ch<='9') {x=10*x+ch-'0';ch=getchar();}
  return x;
}

const int maxn = 100010;

int n,m=27,ans;
char s1[maxn];
int s[maxn],c[maxn],t1[maxn],t2[maxn];
int sa[maxn],ra[maxn],he[maxn];
int dp[maxn][22];

void get_sa() {
  int i,*x=t1,*y=t2;
  for(i=0; i<m; i++) c[i]=0;
  for(i=0; i<n; i++) c[x[i]=s[i]]++;
  for(i=1; i<m; i++) c[i]+=c[i-1];
  for(i=n-1; i>=0; i--) sa[--c[x[i]]]=i;
  for(int k=1; k<=n; k<<=1) {
    int p=0;
    for(i=n-k; i<n; i++) y[p++]=i;
    for(i=0; i<n; i++) if(sa[i]>=k) y[p++]=sa[i]-k;
    for(i=0; i<m; i++) c[i]=0;
    for(i=0; i<n; i++) c[x[y[i]]]++;
    for(i=1; i<m; i++) c[i]+=c[i-1];
    for(i=n-1; i>=0; i--) sa[--c[x[y[i]]]]=y[i];
    swap(x,y);
    p=1,x[sa[0]]=0;
    for(i=1; i<n; i++)
      x[sa[i]]=y[sa[i-1]]==y[sa[i]] && y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
    if(p>=n) break;
    m=p;		 
  }
}

void get_he() {
  int i,j,k=0;
  for(i=1; i<=n; i++) ra[sa[i]]=i;
  for(i=0; i<n; i++) {
    if(k) k--;
    j=sa[ra[i]-1];
    while(s[j+k]==s[i+k]) k++;
    he[ra[i]]=k;
  }
}

void prepare() {
  memset(dp,127/3,sizeof(dp));
  for(int i=1; i<=n; i++)
    dp[i][0]=he[i];
  for(int j=1; j<=20; j++)
    for(int i=1; i+(1<<j-1)<=n; i++)
      dp[i][j]=min(dp[i][j-1],dp[i+(1<<j-1)][j-1]);
}

int lcp(int l, int r) {
  l=ra[l],r=ra[r];//注意取排名
  if(l>r) swap(l,r);
  l++;
  int len=r-l+1;
  int k=(int)(log(len)/log(2));
  return min(dp[l][k],dp[r-(1<<k)+1][k]);
}

int solve() {//纯抄题解
  for(int L=1; L<=n; L++) {
    for(int i=1; i+L<=n; i+=L) {
      int R=lcp(i,i+L);
      ans=max(ans,R/L+1);
      if(i>=L-R%L) ans=max(ans,lcp(i-L+R%L,i+R%L)/L+1);
    }
  }
  return ans;
}

int main() {
  scanf("%s", s1);
  n=strlen(s1);
  for(int i=0; i<n; i++) s[i]=s1[i]-'a'+1;
  n++,get_sa(),n--;
  get_he();
  prepare();
  printf("%d\n", solve());
  return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值