您的位置:首页 > 其它

[后缀数组 枚举 字符串分段] BZOJ 4650 [Noi2016]优秀的拆分

2016-11-10 18:03 369 查看
先求出所有的双倍字串 然后再乱来

我们枚举一半的长度 然后把整个字符串按照长度l分段 

起点分别为 s[1] s[l+1] s[2l+1]  ... 分段后记作 S1 S2 S3 .....

那么双倍的串一定会包含其中两个 我们求 Si Si-1的LCS  Si Si+1的LCP

如果LCS+LCP>=l 那么存在 双倍串 记录一下 这里我用了差分

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#define cl(x) memset(x,0,sizeof(x))
using namespace std;
typedef long long ll;

inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
return *p1++;
}

inline void read(int &x){
char c=nc(),b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

inline int read(char *s){
char c=nc(); int len=0;
for (;!(c>='a' && c<='z');c=nc());
for (;c>='a' && c<='z';s[++len]=c,c=nc()); s[++len]=0; return len-1;
}

const int N=30005;

struct SArray{
int n;
int sa
,t1
,t2
,c
;
int height
,rank
;
inline void SA(char *r,int m){
int *x=t1,*y=t2;
for (int i=0;i<=m;i++) c[i]=0;
for (int i=1;i<=n;i++) c[x[i]=r[i]-'a'+1]++;
for (int i=1;i<=m;i++) c[i]+=c[i-1];
for (int i=n;i;i--) sa[c[x[i]]--]=i;
for (int k=1;k<=n;k<<=1){
int p=0;
for (int i=n-k+1;i<=n;i++) y[++p]=i;
for (int i=1;i<=n;i++) if (sa[i]>k) y[++p]=sa[i]-k;
for (int i=0;i<=m;i++) c[i]=0;
for (int i=1;i<=n;i++) c[x[y[i]]]++;
for (int i=1;i<=m;i++) c[i]+=c[i-1];
for (int i=n;i;i--) sa[c[x[y[i]]]--]=y[i];
swap(x,y);
x[sa[1]]=1; p=1;
for (int i=2;i<=n;i++)
x[sa[i]]=(y[sa[i]]==y[sa[i-1]] && y[sa[i]+k]==y[sa[i-1]+k])?p:++p;
if (p>=n) break;
m=p;
}
}
inline void GetHeight(char *S,int *sa,int n){
int j,k=0;
for (int i=1;i<=n;i++) rank[sa[i]]=i;
for (int i=1;i<=n;height[rank[i++]]=k)
for (k?k--:0,j=sa[rank[i]-1];S[i+k]==S[j+k];)
k++;
}
int st
[20],Log
;
inline void Pre(int n,int *a){
for (int i=2;i<=n;i++) Log[i]=Log[i>>1]+1;
for (int i=1;i<=n;i++)
st[i][0]=a[i];
for (int k=1;k<20;k++)
for (int i=1;i<=n;i++){
st[i][k]=st[i][k-1];
if (i+(1<<(k-1))<=n)
st[i][k]=min(st[i][k],st[i+(1<<(k-1))][k-1]);
}
}
inline int Query(int l,int r){
if (l>r) swap(l,r);
int t=Log[r-l+1];
return min(st[l][t],st[r-(1<<t)+1][t]);
}
inline void Build(char *S,int len){
cl(sa); cl(height); cl(rank); cl(t1); cl(t2);
n=len; SA(S,30);
GetHeight(S,sa,n);
Pre(len,height);
}
inline int LCP(int x,int y){
if (x>n || x<=0 || y>n || y<=0) return 0;
if (rank[x]>rank[y]) swap(x,y);
return Query(rank[x]+1,rank[y]);
}
}suf,pre;

struct BIT{
int c
,maxn;
void init(int n){
maxn=n; for (int i=1;i<=maxn;i++) c[i]=0;
}
void add(int s,int t,int r){
if (s>t) return;
c[s]+=r; if (t+1<=maxn) c[t+1]-=r;
}
void calc(){
for (int i=2;i<=maxn;i++)
c[i]+=c[i-1];
}
}lft,rgt;

char str
;
int n;
ll Ans;

int main(){
int T,lcp,lcs;
freopen("t.in","r",stdin);
freopen("t.out","w",stdout);
read(T);
while (T--){
n=read(str);
lft.init(n); rgt.init(n);
suf.Build(str,n);
reverse(str+1,str+n+1);
pre.Build(str,n);
reverse(str+1,str+n+1);
for (int i=1;i<=(n>>1);i++){
for (int j=1;j<=n;j+=i){
lcp=min(i,suf.LCP(j,j+i));
lcs=min(i,pre.LCP(n-(j-1)+1,n-(j+i-1)+1));
if (lcp+lcs>=i){
rgt.add(j-lcs,min(j-lcs+(lcp+lcs-i),j-1),1);
lft.add(max(j+i-1+lcp-(lcp+lcs-i),j+i),j+i-1+lcp,1);
}
}
}
lft.calc(); rgt.calc();
Ans=0;
for (int i=1;i<n;i++)
Ans+=(ll)lft.c[i]*rgt.c[i+1];
printf("%lld\n",Ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: