关于后缀数组分块的一个小问题

P1117 [NOI2016] 优秀的拆分

感觉端点的选取应该是轮换对称的?但是不对
by Cupids_Bow @ 2022-05-10 22:04:39


没过能不能看下代码((
by w23c3c3 @ 2022-05-10 22:10:14


@[w23c3c3](/user/109942) ```cpp #include<bits/stdc++.h> using namespace std; using ll=long long; constexpr int N=1e5+5; int _=1; struct SA{ int n,m; char s[N]; int sa[N],rk[N],height[N],h[N]; int minn[N][21],lg[N]; void init(int _n,int _m){ n=_n; m=_m; } void buildsa(){ static int x[N*2],y[N*2],c[N]; for(int i=1;i<=m;i++) c[i]=0; for(int i=1;i<=n*2;i++) x[i]=y[i]=0; for(int i=1;i<=n;i++) y[i]=0; for(int i=1;i<=n;i++) c[x[i]=(s[i]-'a'+1)]++; for(int i=2;i<=m;i++) c[i]+=c[i-1]; for(int i=n;i>=1;i--) sa[c[x[i]]--]=i; for(int k=1;k<=n;k<<=1){ int num=0; for(int i=n-k+1;i<=n;i++) y[++num]=i; for(int i=1;i<=n;i++) if(sa[i]>k) y[++num]=sa[i]-k; for(int i=1;i<=m;i++) c[i]=0; for(int i=1;i<=n;i++) c[x[i]]++; for(int i=2;i<=m;i++) c[i]+=c[i-1]; for(int i=n;i>=1;i--) sa[c[x[y[i]]]--]=y[i],y[i]=0; swap(x,y); x[sa[1]]=1; num=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])?num:++num; if(num==n) break; m=num; } for(int i=1;i<=n;i++) rk[sa[i]]=i; } void buildheight(){ int k=0; for(int i=1;i<=n;i++){ if(rk[i]==1) continue; if(k) --k; int j=sa[rk[i]-1]; while(j+k<=n&&i+k<=n&&s[i+k]==s[j+k]) k++; height[rk[i]]=k; } for(int i=2;i<=n;i++) lg[i]=lg[i>>1]+1; for(int i=1;i<=n;i++) minn[i][0]=height[i]; for(int j=1;j<=20;j++) for(int i=1;i+(1<<j)-1<=n;i++) minn[i][j]=min(minn[i][j-1],minn[i+(1<<(j-1))][j-1]); } int get_lcp(int l,int r){ l=rk[l],r=rk[r]; if(l>r) swap(l,r); l++; int k=lg[r-l+1]; return min(minn[l][k],minn[r-(1<<k)+1][k]); } }sa1,sa2; int n; int f[N],g[N]; void work(){ cin>>sa1.s+1; n=strlen(sa1.s+1); for(int i=1;i<=n;i++) f[i]=g[i]=0; sa1.init(n,26); sa2.init(n,26); for(int i=1;i<=n;i++) sa2.s[i]=sa1.s[n-i+1]; sa1.buildsa(); sa2.buildsa(); sa1.buildheight(); sa2.buildheight(); for(int len=1;len<=n/2;len++){ for(int i=len;i+len<=n;i+=len){ int l=i,r=i+len; int L=n-(r-1)+1,R=n-(l-1)+1; int lcp=min(len,sa1.get_lcp(l,r)); int lcs=min(len-1,sa2.get_lcp(L,R)); if(lcp+lcs>=len){ f[r+lcp-(lcp+lcs-len+1)]++; f[r+lcp]--; g[l-lcs]++; g[l-lcs+(lcp+lcs-len+1)]--; } } } for(int i=1;i<=n;i++) f[i]+=f[i-1],g[i]+=g[i-1]; ll ans=0; for(int i=2;i<=n;i++) ans+=1ll*f[i-1]*g[i]; cout<<ans<<'\n'; } int main(){ ios::sync_with_stdio(0); cin.tie(0);cout.tie(0); cin>>_; while(_--){ work(); } return true&&false; } ``` 这份是AC的 ```cpp #include<bits/stdc++.h> using namespace std; using ll=long long; constexpr int N=1e5+5; int _=1; struct SA{ int n,m; char s[N]; int sa[N],rk[N],height[N],h[N]; int minn[N][21],lg[N]; void init(int _n,int _m){ n=_n; m=_m; } void buildsa(){ static int x[N*2],y[N*2],c[N]; for(int i=1;i<=m;i++) c[i]=0; for(int i=1;i<=n*2;i++) x[i]=y[i]=0; for(int i=1;i<=n;i++) y[i]=0; for(int i=1;i<=n;i++) c[x[i]=(s[i]-'a'+1)]++; for(int i=2;i<=m;i++) c[i]+=c[i-1]; for(int i=n;i>=1;i--) sa[c[x[i]]--]=i; for(int k=1;k<=n;k<<=1){ int num=0; for(int i=n-k+1;i<=n;i++) y[++num]=i; for(int i=1;i<=n;i++) if(sa[i]>k) y[++num]=sa[i]-k; for(int i=1;i<=m;i++) c[i]=0; for(int i=1;i<=n;i++) c[x[i]]++; for(int i=2;i<=m;i++) c[i]+=c[i-1]; for(int i=n;i>=1;i--) sa[c[x[y[i]]]--]=y[i],y[i]=0; swap(x,y); x[sa[1]]=1; num=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])?num:++num; if(num==n) break; m=num; } for(int i=1;i<=n;i++) rk[sa[i]]=i; } void buildheight(){ int k=0; for(int i=1;i<=n;i++){ if(rk[i]==1) continue; if(k) --k; int j=sa[rk[i]-1]; while(j+k<=n&&i+k<=n&&s[i+k]==s[j+k]) k++; height[rk[i]]=k; } for(int i=2;i<=n;i++) lg[i]=lg[i>>1]+1; for(int i=1;i<=n;i++) minn[i][0]=height[i]; for(int j=1;j<=20;j++) for(int i=1;i+(1<<j)-1<=n;i++) minn[i][j]=min(minn[i][j-1],minn[i+(1<<(j-1))][j-1]); } int get_lcp(int l,int r){ l=rk[l],r=rk[r]; if(l>r) swap(l,r); l++; int k=lg[r-l+1]; return min(minn[l][k],minn[r-(1<<k)+1][k]); } }sa1,sa2; int n; int f[N],g[N]; void work(){ cin>>sa1.s+1; n=strlen(sa1.s+1); for(int i=1;i<=n;i++) f[i]=g[i]=0; sa1.init(n,26); sa2.init(n,26); for(int i=1;i<=n;i++) sa2.s[i]=sa1.s[n-i+1]; sa1.buildsa(); sa2.buildsa(); sa1.buildheight(); sa2.buildheight(); for(int len=1;len<=n/2;len++){ for(int i=1;i+len<=n;i+=len){ int l=i,r=i+len; int L=n-(r-1)+1,R=n-(l-1)+1; int lcp=min(len,sa1.get_lcp(l,r)); int lcs=min(len-1,sa2.get_lcp(L,R)); if(lcp+lcs>=len){ f[r+lcp-(lcp+lcs-len+1)]++; f[r+lcp]--; g[l-lcs]++; g[l-lcs+(lcp+lcs-len+1)]--; } } } for(int i=1;i<=n;i++) f[i]+=f[i-1],g[i]+=g[i-1]; ll ans=0; for(int i=2;i<=n;i++) ans+=1ll*f[i-1]*g[i]; cout<<ans<<'\n'; } int main(){ ios::sync_with_stdio(0); cin.tie(0);cout.tie(0); cin>>_; while(_--){ work(); } return true&&false; } ``` 这份是WA的
by Cupids_Bow @ 2022-05-10 22:13:47


@[Cupids_Bow](/user/96720) 我测出来你是因为 l-lcs<0 了。
by w23c3c3 @ 2022-05-10 22:24:27


@[w23c3c3](/user/109942) 嗷嗷,好像还是多组数据初始挂了,最后还是没注意到这个,感谢dalao/bx
by Cupids_Bow @ 2022-05-10 22:33:54


@[Cupids_Bow](/user/96720) 诶是不是因为 l=1 的时候, R 就 =0,然后在 getlcp 的时候会算一些奇怪东西(?
by w23c3c3 @ 2022-05-10 22:36:09


哦 R 是 n+1。 这样就会出现上次没清空然后引发求 rk[L],rk[R] 的最小值出问题。
by w23c3c3 @ 2022-05-10 22:38:05


@[w23c3c3](/user/109942) 刚刚初始化把rk清了就没问题了,(偷懒把人偷炸了
by Cupids_Bow @ 2022-05-10 22:41:29


想的是sa和rk会重新求一遍就只清了辅助数组
by Cupids_Bow @ 2022-05-10 22:42:29


/fad
by w23c3c3 @ 2022-05-10 22:43:06


| 下一页