codeforces 653F

原題

原題鏈接

題目大意

給你一個長度爲n5105 的只含有左右括號字符串,問,有多少個不同的合法的字串滿足正確的括號序。

滿足條件的括號序:
1) A=”()”
2) (A)
3) AA

解題思路

我們可以把( 當成+1,把) 當成-1,那麼可以做一個前綴和si ,如果要求以i 位置開頭的合法的括號序的個數就是求有多少個i<jn 滿足sj=si1,ikj,sksi1 .

這個方法是沒有去重的,但是我們可以發現,我們用後綴數組求了height 之後,j 的可選範圍,就變成了i+heighti+1jn ,其他條件一樣。

現在問題就是要滿足ikj,sksi1 ,這個條件了。我們可以用Rmq來維護區間的s 最小值,然後二分判斷最大可選的j ,在哪個位置就行了。

參考代碼

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define maxn 500005
#define maxsq 22
#define pb(i) push_back(i)
#define ll long long
using namespace std;

vector <int> p[maxn*2];

int height[maxn],sa[maxn],rank[maxn],x[maxn],y[maxn],wv[maxn],wss[maxn];

int n,s[maxn];

char ch[maxn];

int Log[maxn],f[maxn][maxsq];

ll ans;

bool compare(int *rank,int i,int j,int l){
    return rank[i]==rank[j] && rank[i+l]==rank[j+l];
}

void SA(){
    int i,j,m=')'+1,p;
    fo(i,1,n) wss[x[i]=ch[i]]++;
    fo(i,1,m) wss[i]+=wss[i-1];
    fo(i,1,n) sa[wss[x[i]]--]=i;
    for(j=1,p=0;p<n;m=p,j*=2) {
        for(p=0,i=n-j+1;i<=n;i++) y[++p]=i;
        for(i=1;i<=n;i++) if (sa[i]-j>0) y[++p]=sa[i]-j;
        for(i=1;i<=n;i++) wv[i]=x[y[i]];
        for(i=1;i<=m;i++) wss[i]=0;
        for(i=1;i<=n;i++) wss[wv[i]]++;
        for(i=1;i<=m;i++) wss[i]+=wss[i-1];
        for(i=n;i>=1;i--) sa[wss[wv[i]]--]=y[i];
        swap(x,y);
        for(x[sa[1]]=1,p=1,i=2;i<=n;i++)
            x[sa[i]]=compare(y,sa[i-1],sa[i],j) ? p : ++p;
    }
}

void get_height(){
    fo(i,1,n) rank[sa[i]]=i;
    int j,k=0;
    for(int i=1;i<=n;height[rank[i++]]=k)
        for(k ? k-- : 0,j=sa[rank[i]-1];ch[i+k]==ch[j+k];k++);
}

int calc(int x,int y){
    int dis=y-x+1;
    return min(f[x][Log[dis]],f[y-(1 << Log[dis])+1][Log[dis]]);
}

int main(){
    scanf("%d",&n);
    char c=getchar();
    while (c!='(' && c!=')') c=getchar();
    fo(i,1,n) {
        ch[i]=c;
        if (c=='(') s[i]=s[i-1]+1;
        else s[i]=s[i-1]-1;
        f[i][0]=s[i];
        c=getchar();
        p[s[i]+n].pb(i);
    }
    fo(i,2,n) Log[i]=Log[i >> 1]+1;
    fo(i,1,Log[n]) 
        fo(j,1,n-(1 << i)+1) f[j][i]=min(f[j][i-1],f[j+(1 << (i-1))][i-1]);
    SA();
    get_height();
    fo(i,1,n) {
        int w=sa[i];
        if (ch[w]==')') continue;
        int fr=w+height[i];
        if (fr>n) continue;
        int to=w;
        int l=w,r=n;
        while (l<=r) {
            int mid=(l+r) >> 1;
            if (calc(w,mid)>=s[w-1]) {
                to=mid;
                l=mid+1;
            } else r=mid-1;
        }
        if (fr>to) continue;
        ans+=upper_bound(p[s[w-1]+n].begin(),p[s[w-1]+n].end(),to)-lower_bound(p[s[w-1]+n].begin(),p[s[w-1]+n].end(),fr);
    }
    printf("%I64d",ans);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章