HDU5785 Interesting

題目連接:http://acm.hdu.edu.cn/showproblem.php?pid=5785


【題意】已知一個string s,對於求滿足s[i,j],s[j+1,k]都是迴文串所有i*k的和。


【分析】用Manacher算法獲取迴文串的長度,相應轉換成迴文串半徑。採用題解的方法,計算以i爲起點的所有迴文串終點和cntR[i],以及以i爲終點的所有迴文串起點和cntL[i]。於是答案就是遍歷0到strlen(s)-1計算cntL[i]*cntR[i+1]的和。在計算cntR和cntL的時候,暴力做會超時,利用標記數組O(n)來處理才過的。這裏對cntR的標記進行說明,cntL的標記同理。對於一個迴文串s[l,r],標記sumtag[l]+=r,傳遞時sumtag[l+1]=sumtag[l]-1。由於標記只需要傳到(l+r)/2,所以sum[(l+r)/2+1]-=(l+r)/2-1。考慮到區間重疊的問題,以sumcnt[l]標記覆蓋l的區間個數,於是每次處理時sumcnt[l]++,sum[(l+r)/2+1]--。這樣每次傳遞時改爲sumtag[l+1]=sumtag[l]-sumcnt[l]。(ps:注意中間值的取值,這裏僅作說明不一定正確,同時奇偶長度的串需要分開處理)。


【代碼】

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define LL long long
#define MAXN 1001000
const int mod=1e9+7;
int p[MAXN*2];
char str[MAXN*2];
LL sumtagR[MAXN];
LL sumcntR[MAXN];
LL sumtagL[MAXN];
LL sumcntL[MAXN];
LL cntL[MAXN];
LL cntR[MAXN];
int len,id;
void init(){
    memset(sumtagR,0,sizeof(sumtagR));
    memset(sumtagL,0,sizeof(sumtagL));
    memset(sumcntR,0,sizeof(sumcntR));
    memset(sumcntL,0,sizeof(sumcntL));
    len=strlen(str),id=0;
    for(int i=len;i>=0;i--){
        str[i+i+2]=str[i];
        str[i+i+1]='#';
    }
    str[0]='*';
    for(int i=2;i<2*len+1;++i){
        int l,r;
        if(p[id]+id>i)
            p[i]=min(p[2*id-i],p[id]+id-i);
        else
            p[i]=1;
        while(str[i-p[i]]==str[i+p[i]])
            ++p[i];
        if(id+p[id]<i+p[i])
            id=i;
        if(str[i]=='#'){
            l=i/2-(p[i]-1)/2+1,r=i/2+(p[i]-1)/2;
            //printf("%d %d %d %d\n",l,r,i/2+1,i/2);
            sumtagR[l]=(sumtagR[l]+r)%mod;
            sumtagR[i/2+1]=(sumtagR[i/2+1]-i/2)%mod;
            sumcntR[l]++;
            sumcntR[i/2+1]--;
            sumtagL[r]=(sumtagL[r]+l)%mod;
            sumtagL[i/2]=(sumtagL[i/2]-i/2-1)%mod;
            sumcntL[r]++;
            sumcntL[i/2]--;
        }
        else{
            l=i/2-(p[i]-1)/2,r=i/2+(p[i]-1)/2;
            //printf("%d %d %d %d\n",l,r,i/2+1,i/2-1);
            sumtagR[l]=(sumtagR[l]+r)%mod;
            sumtagR[i/2+1]=(sumtagR[i/2+1]-i/2+1)%mod;
            sumcntR[l]++;
            sumcntR[i/2+1]--;
            sumtagL[r]=(sumtagL[r]+l)%mod;
            sumtagL[i/2-1]=(sumtagL[i/2-1]-i/2-1)%mod;
            sumcntL[r]++;
            sumcntL[i/2-1]--;
        }
    }
    for(int i=1;i<=len;++i){
        cntR[i]=sumtagR[i];
        sumtagR[i+1]=((sumtagR[i+1]+sumtagR[i]-sumcntR[i])%mod+mod)%mod;
        sumcntR[i+1]=(sumcntR[i+1]+sumcntR[i])%mod;
    }
    for(int i=len;i;i--){
        cntL[i]=sumtagL[i];
        sumtagL[i-1]=((sumtagL[i-1]+sumtagL[i]+sumcntL[i])%mod+mod)%mod;
        sumcntL[i-1]=(sumcntL[i-1]+sumcntL[i])%mod;
    }
}
int main(){
    while(~scanf("%s",str)){
        init();
        LL ans=0;
        for(int i=1;i<len;++i)
            ans=(ans+(cntL[i]*cntR[i+1])%mod)%mod;
        cout<<ans<<endl;
    }
}


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