Hdu 5785 Interesting(Manacher+區間處理)

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

思路:

1.L[i]表示以i開始的所有迴文的結束位置和,R[i]表示以i位置結尾的所有迴文開始位置和,則答案爲sigma(R[i-1]*L[i])(x1*y1+x1*y2+...x1*yn+x2*y1+x2*y2+.....x2*yn+......=(x1+x2+....xn)*y1+(x1+x2+...+xn)*y2+......=(x1+x2+.....+xn)*(y1+y2+....+ym))。

2.首先使用Manacher算法求出以每個字母i爲對稱軸的迴文半徑pos[i]。對於L:則對應i,字符串[i-pos[i],i+pos[i]]、[i-pos[i]+1,i+pos[i]-1]、[i-pos[i]+2,i+pos[i]-2]、.......、[i,i]爲迴文串,對應位置i-pos[i]應加上i+pos[i]、i-pos[i]+1應加上i+pos[i]-1、.....、i應加上i。即爲對應每一個區間[i-pos[i],i]依次加上以i+pos[i]爲首項,-1爲公差的等差數列。R數組同理。

3.若對區間[l,r]加上同一個數x,則只需設置標記:對應首項a[l]+=x,尾項a[r+1]-=x,依次遞推即可。若對區間加上一首項爲x,公差爲d的一等差數列,則需設置一數組sub,表示每項的增量。設置a[l]+=x,a[r+1]-=等差數列尾項,sub[l]+=-d,sub[r+1]+=d。依次遞推出增量sub[i]+=sub[i-1],對於每項a[i],a[i]+=a[i-1]-sub[i]。

4.由於數組操作爲添加符號之後的字符串,則對於原串ansL[i]=L[i]/2,ansR[i]=R[i]/2。由於最終結果取模,此處應乘以逆元500000004(錯了好久。。。。)。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define debug
using namespace std;

typedef long long LL;

const int inv=500000004;
const int mod=1000000007;
const int maxn=2000000+5;

int l;
LL Mp[maxn];
LL L[maxn],subL[maxn];
LL R[maxn],subR[maxn];
char Ma[maxn],st[maxn];
LL ansL[maxn],ansR[maxn];

void Manacher(char s[],int len)
{
    l=0;
    Ma[l++]='$';
    Ma[l++]='#';
    for(int i=0; i<len; i++)
    {
        Ma[l++]=s[i];
        Ma[l++]='#';
    }
    Ma[l]=0;
    for(int i=0;i<=l;i++) Mp[i]=0;
    LL mx=0,id=0;
    for(int i=0; i<l; i++)
    {
        Mp[i]=mx>i?min(Mp[2*id-i],mx-i):1;
        while(Ma[i+Mp[i]]==Ma[i-Mp[i]]) Mp[i]++;
        if(i+Mp[i]>mx)
        {
            mx=i+Mp[i];
            id=i;
        }
    }
}

void solve()
{
    for(int i=0; i<=l; i++)
    {
        L[i]=R[i]=subL[i]=subR[i]=0;
    }

    for(int i=1; i<l; i++)
    {
        Mp[i]--;

        L[i-Mp[i]]+=i+Mp[i];
        L[i+1]-=i;
        subL[i-Mp[i]+1]+=1;
        subL[i+1]-=1;

        R[i+Mp[i]]+=i-Mp[i];
        R[i-1]-=i;
        subR[i+Mp[i]-1]-=1;
        subR[i-1]+=1;

    }

    for(int i=l-1; i>=1; i--)
    {
        subR[i]+=subR[i+1];subR[i]%=mod;
        R[i]+=R[i+1]-subR[i]+mod;R[i]%=mod;

    }

    for(int i=1; i<l; i++)
    {
        subL[i]+=subL[i-1];subL[i]%=mod;
        L[i]+=L[i-1]-subL[i]+mod;L[i]%=mod;
    }

    int cnt=0;
    for(int i=2; i<l; i+=2)
    {
        ansL[++cnt]=L[i]*inv%mod;
        ansR[cnt]=R[i]*inv%mod;
    }

    LL ans=0;
    for(int i=2; i<=cnt; i++)
    {
        ans+=(LL)ansR[i-1]*(LL)ansL[i];
        ans%=mod;
    }
    printf("%lld\n",ans);
}

int main()
{
#ifdef debu
    freopen("in.txt","r",stdin);
    freopen("out.out","w",stdout);
#endif // debug
    while(scanf("%s",st)!=EOF)
    {
        Manacher(st,strlen(st));
        solve();
    }
    return 0;
}




發佈了381 篇原創文章 · 獲贊 6 · 訪問量 14萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章