Codeforces 873F - Forbidden Indices 後綴數組

題意:子串的長度*子串出現的次數爲這個子串的值,求最大值。還有個約束條件串t,若t[i]=='1',則以該位置結尾的子串不能使用

題解:

把串倒轉過來,這樣以該位置結尾不能用的條件轉化爲以該位置開頭的子串不能用

若先不考慮約束條件,該題的答案就是某一子串的長度*該子串出現的次數

而出現次數非常好求,根據做完後綴數組後的height[]數組來。

l[i]爲i左邊第一個小於height[i]的位置,r[i]爲i右邊第一個小於height[i]的位置,出現次數就是r[i]-l[i];

l,r數組用單調棧O(n)的就能求出來。現在考慮約束條件,根據串t,用sum[]前綴和求出sa數組的‘1’的總個數,爲‘1’的串不能用。最後出現次數減去就是l[i]到r[i]的1的個數(不能用的串的個數)就行

#include<bits/stdc++.h>
#define rint register int
#define inv inline void
#define ini inline int
#define maxn 2000050
typedef long long ll;
using namespace std;
char s[maxn],t[maxn];
int y[maxn],x[maxn],c[maxn],sa[maxn],rk[maxn],height[maxn],wt[30];
int n,m;
inv putout(int x) {
    if(!x) {
        putchar(48);
        return;
    }
    rint l=0;
    while(x) wt[++l]=x%10,x/=10;
    while(l) putchar(wt[l--]+48);
}
inv get_SA() {
    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 sum[maxn],st[maxn],l[maxn],r[maxn];
int main() {
    scanf("%d",&n);
    scanf("%s%s",s+1,t+1);
    reverse(s+1,s+n+1);
    reverse(t+1,t+n+1);
    m=200;
    get_SA();
    get_height();
    for(int i=1;i<=n;i++){
        sum[i]+=sum[i-1];

        if(t[sa[i]]=='1') sum[i]++;
        //printf("@%d\n",sum[i]);
    }
    ll ans=0;
    for(int i=1;i<=n;i++){
        if(t[i]=='0'){
            ans=n-i+1;
            break;
        }
    }
    int tail=0;
    for(int i=1;i<=n;i++){
        while(tail>0&&height[st[tail]]>height[i]){
            r[st[tail]]=i;
            tail--;
        }
        st[++tail]=i;
    }
    while(tail>0){
        r[st[tail]]=n+1;
        tail--;
    }
    tail=0;
    for(int i=n;i>=1;i--){
        while(tail>0&&height[st[tail]]>height[i]){
            l[st[tail]]=i;
            tail--;
        }
        st[++tail]=i;
    }
    while(tail>0){
        l[st[tail]]=0;
        tail--;
    }

    for(int i=1;i<=n;i++){
        //printf("!%d %d %d %d\n",l[i],r[i],height[i],(sum[r[i]-1]-sum[l[i]]));
        ll tmp=r[i]-l[i];
        tmp-=(sum[r[i]-1]-sum[l[i]-1]);
        ans=max(ans,height[i]*tmp);
    }
    printf("%lld\n",ans);
}

 

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