首页 > 其他分享 >SP10570

SP10570

时间:2023-04-25 18:33:51浏览次数:42  
标签:rnk int SP10570 maxm Len prnk sa

后缀数组做法。

用不同的分隔字符将 \(n\) 个串连接起来, 如 \(\texttt{abcdefg}\) 、 \(\texttt{qaq}\) 、 \(\texttt{qwq}\) 拼成 \(\texttt{abcdefgAqaqBqwqC}\)。

求出新串的后缀数组和 height 数组,然后二分答案,问题转变为判断是否有一个长度为 \(p\) 的串在所有的串中出现,判断方法是扫描整个 height 数组,将它分为若干个段,每个段的最初 \(p\) 个字符均相同,如果该段包含的所有串,那么 \(p\) 就是满足条件的。

#include <bits/stdc++.h>
#define _for(I,A,B) for(int I=(A); I<=(B); I++)
#define _rof(I,A,B) for(int I=(A); i>=(B); I--)
using namespace std;
const int N=4e5+11;
int sa[N], height[N], rnk[N];
struct Suffix_Array{
  int prnk[N], y[N], c[N];
  bool issame(int x, int y, int w){
    return prnk[x]==prnk[y]&&prnk[x+w]==prnk[y+w];
  }
  void solve(char *A, int Len){
    _for(i,0,Len+111) sa[i]=height[i]=rnk[i]=prnk[i]=0;
    int m=300, maxm=300;
    _for(i,0,maxm+11) c[i]=0;
    _for(i,1,Len) c[rnk[i]=A[i]]++;
    _for(i,1,maxm) c[i]+=c[i-1];
    _rof(i,Len,1) sa[c[rnk[i]]--]=i;
    for(int w=1; w<=Len; w<<=1,maxm=m){
      m=0;
      _for(i,Len-w+1,Len) y[++m]=i;
      _for(i,1,Len) if(sa[i]>w) y[++m]=sa[i]-w;
      _for(i,1,maxm+11)c[i]=0;
      _for(i,1,Len) c[rnk[y[i]]]++;
      _for(i,1,maxm) c[i]+=c[i-1];
      _rof(i,Len,1) sa[c[rnk[y[i]]]--]=y[i];
      memcpy(prnk,rnk,sizeof(int)*(Len+9)),m=0;
      _for(i,1,Len) rnk[sa[i]]=issame(sa[i],sa[i-1],w)?m:++m;
      if(m==Len)break;
    }
    for(int i=1, k=0, j; i<=Len; i++){
      if(k)k--;
      j=sa[rnk[i]-1];
      while(A[i+k]==A[j+k])k++;
      height[rnk[i]]=k;
    }
  }
}SA;
char s[N<<3], buf[N];
int n, slen, id[N], MAX, idcnt, flag[N];
bool check(int l, int r){
  int CNT=0; idcnt++;
  _for(i,l,r) if(flag[id[sa[i]]]!=idcnt&&id[sa[i]]!=0)
    flag[id[sa[i]]]=idcnt, CNT++;
  return CNT>=n;
}
bool checker(int Length){
  for(int L=1, R=2; R<=slen+1; R++){
    if(height[R]<Length||R==slen+1){
      if(check(L,R-1))return 1;
      L=R;
    }
  }
  return 0;
}
void sol(){
  scanf("%d", &n), slen=0, MAX=1145141;
  _for(i,1,n){
    scanf(" %s", buf);
    int buflen=strlen(buf);
    MAX=min(MAX, buflen);
    _for(j,0,buflen-1) s[++slen]=buf[j], id[slen]=i;
    s[++slen]='A'+i-1, id[slen]=0;
  }
  s[slen+1]=s[slen+2]='\0';
  id[slen+1]=id[slen+2]=0;
  SA.solve(s, slen);
  int ans=0, l=0, r=MAX;
  while(l<=r){
    int mid=l+r>>1;
    if(checker(mid))ans=mid,l=mid+1;
    else r=mid-1;
  }
  printf("%d\n", ans);
}
int main(){
  #ifdef B
    freopen("text.in","r",stdin);
    freopen("text.out","w",stdout);
  #endif
  int T; scanf("%d", &T);
  while(T--) sol();
  return 0;
}

标签:rnk,int,SP10570,maxm,Len,prnk,sa
From: https://www.cnblogs.com/dadidididi/p/17353510.html

相关文章