題意:一個主串s,q個短串w,問有多少個短串使得w [1..i]和w [i + 1..end]都出現在s中,而w [1..i]出現在w之前[i + 1..end](沒有重疊)
題解:
只要考慮w [1..i]的最左側出現和w [i + 1..end]的最右側位置就行了。因此,記g [j][i]是第j個串,w [1..i]在s中最左邊出現的位置,而f[j][i]是第j個串,w [i + 1..end]在s中最右邊左邊界位置。一旦有了f和g,我們就可以輕鬆地檢查每個串是否符合條件
我們對s使用後綴數組(並且將s取反以計算f)。現在如何計算g:對於每個前綴(從i = 1開始),我們找到範圍[a,b],使得sa [a..b]對應於s中以w [1..i開頭的索引]。我們從上一個計算範圍在二分搜索答案。然後,我們在sa [a..b]上運行RMQ查詢以找到最小索引(這是我們想要的g [i])。反之亦然
具體看代碼,蠻簡單的。
#include<bits/stdc++.h>
#define rint register int
#define inv inline void
#define ini inline int
using namespace std;
const int maxn=200050;
char s[maxn],t[maxn];
int y[maxn],x[maxn],c[maxn],sa[maxn],rk[maxn],height[maxn],wt[30];
int n,m;
inv get_SA() {
for(int i=1;i<=m;i++) c[i]=0;
for (rint i=1; i<=n; ++i) ++c[x[i]=s[i]];
for (rint i=2; i<=m; ++i) c[i]+=c[i-1];
for (rint i=n; i>=1; --i) sa[c[x[i]]--]=i;
for (rint k=1; k<=n; k<<=1) {
rint num=0;
for (rint i=n-k+1; i<=n; ++i) y[++num]=i;
for (rint i=1; i<=n; ++i) if (sa[i]>k) y[++num]=sa[i]-k;
for (rint i=1; i<=m; ++i) c[i]=0;
for (rint i=1; i<=n; ++i) ++c[x[i]];
for (rint i=2; i<=m; ++i) c[i]+=c[i-1];
for (rint 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 (rint 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;
}
}
inv get_height() {
rint k=0;
for (rint i=1; i<=n; ++i) rk[sa[i]]=i;
for (rint i=1; i<=n; ++i) {
if (rk[i]==1) continue;//第一名height爲0
if (k) --k;//h[i]>=h[i-1]-1;
rint j=sa[rk[i]-1];
while (j+k<=n && i+k<=n && s[i+k]==s[j+k]) ++k;
height[rk[i]]=k;//h[i]=height[rk[i]];
}
}
int mmin[maxn][20];
void RMQ_ST(){
for(int i=1;i<=n;i++){
mmin[i][0]=sa[i];
}
int end_j=log(n+0.0)/log(2.0);
int end_i;
for(int j=1;j<=end_j;j++){
end_i=n+1-(1<<j);
for(int i=1;i<=end_i;i++){
mmin[i][j]=min(mmin[i][j-1],mmin[i+(1<<(j-1))][j-1]);
}
}
}
int QueryMin(int L,int R){
if(L==-1||R==-1) return -1;
int k=log(R-L+1.0)/log(2.0);
return min(mmin[L][k],mmin[R-(1<<k)+1][k]);
}
int g[105][1005],f[105][1005];
int find_first(int li,int ri,int sz,char c){
if(li==-1||ri==-1) return -1;
int l=li,r=ri,ans=-1;
while(l<=r){
int mid=l+r>>1;
if(s[sa[mid]+sz]==c) ans=mid,r=mid-1;
else if(s[sa[mid]+sz]<c) l=mid+1;
else r=mid-1;
}
return ans;
}
int find_last(int li,int ri,int sz,char c){
if(li==-1||ri==-1) return -1;
int l=li,r=ri,ans=-1;
while(l<=r){
int mid=l+r>>1;
if(s[sa[mid]+sz]==c) ans=mid,l=mid+1;
else if(s[sa[mid]+sz]<c) l=mid+1;
else r=mid-1;
}
return ans;
}
int main(){
int q;
scanf("%s",s+1);
n=strlen(s+1);
m=200;
get_SA();
get_height();
RMQ_ST();
scanf("%d",&q);
vector<pair<string,string>>vq(q+1);
for(int i=1;i<=q;i++){
string ss="";
scanf("%s",t);
int nz=strlen(t);
for(int i=0;i<nz;i++) ss+=t[i];
vq[i].first=ss;
reverse(ss.begin(),ss.end());
vq[i].second=ss;
}
for(int i=1;i<=q;i++){
int l=1,r=n;
//printf("@\n");
for(int j=0;j<vq[i].first.size()-1;j++){
int fl=find_first(l,r,j,vq[i].first[j]);
int fr=find_last(l,r,j,vq[i].first[j]);
//
g[i][j+1]=QueryMin(fl,fr);
l=fl;r=fr;
}
}
for(int i=1;i<=n/2;i++) swap(s[i],s[n-i+1]);
get_SA();
get_height();
RMQ_ST();
for(int i=1;i<=q;i++){
int l=1,r=n;
for(int j=0;j<vq[i].second.size()-1;j++){
int fl=find_first(l,r,j,vq[i].second[j]);
int fr=find_last(l,r,j,vq[i].second[j]);
if(QueryMin(fl,fr)==-1) f[i][j+1]=-1;
else f[i][j+1]=n-j-QueryMin(fl,fr)+1;
//printf("!%d %d %d %d\n",i,fl,fr,f[i][j+1]);
l=fl;r=fr;
}
}
int ans=0;
for(int i=1;i<=q;i++){
int sz=vq[i].first.size();
for(int j=1;j<sz;j++){
if(g[i][j]!=-1&&f[i][sz-j]!=-1&&f[i][sz-j]>g[i][j]+j-1){
//printf("!%d %d qian:%d hou:%d\n",i,j,g[i][j],f[i][sz-j]);
ans++;
break;
}
}
}
printf("%d\n",ans);
}