codeforces E - Martian Strings 後綴數組

題意:一個主串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);
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章