HDU 5785 Interesting(manacher 前缀和On处理合值)

来源:互联网 发布:关闭apache 保持连接 编辑:程序博客网 时间:2024/06/17 07:11

Interesting


Problem Description
Alice get a string S. She thinks palindrome string is interesting. Now she wanna know how many three tuple (i,j,k) satisfy1ij<klength(S), S[i..j] and S[j+1..k] are all palindrome strings. It's easy for her. She wants to know the sum of i*k of all required three tuples. She can't solve it. So can you help her? The answer may be very large, please output the answer mod 1000000007.

A palindrome string is a string that is same when the string is read from left to right as when the string is read from right to left.
 

Input
The input contains multiple test cases.

Each test case contains one string. The length of string is between 1 and 1000000. String only contains lowercase letter.
 

Output
For each test case output the answer mod 1000000007.
 

Sample Input
aaaabc
 

Sample Output
148


题意:

给出一个字符串,要求所有相邻回文串的左边回文串的左下标和右边回文串的右下标的乘积和

分析:

有趣的字符串题目,首先解决回文串问题,直接用manacher扫一遍,得到每个点的半径,很容易就观察到对于两个相邻的回文串来说答案的贡献就是Lindex*Rindex,那么现在要解决的问题就是如何统计所有贡献值和快速求出答案。

设以i为回文串右端点的贡献值为L[i],以i为回文串左端点的贡献值为R[i].

现在我们处理奇数个数的回文串,设j为回文串中点,那么的到j对L[i]的贡献为j-(i-j),对式子进行一下变形,再考虑所有包括i的中心j,设r为j的回文串半径,得到以下式子:

这里的i和j代表的是原串当中的下标位置+1

同理可以得到R[i]的计算方法,这里不赘述。

再考虑偶数回文串情况,得到以下式子:


这里的i和j代表的是进行manacher之后的位置,相当于加1之后乘2

同理可以的到R[i]的计算方法。

对于奇数串和偶数串的L[i]和R[i]需要进行合并计数

继续观察式子,发现我们只需要对每个合法的j进行一个区间维护次数k和贡献值j就能对于每个L[i]和R[i]进行统计,这里如果直接用树状数组进行统计,可能会因不可描述的原因TLE,考虑一个前缀和的做法,即对于每个区间,只更新左端点和右端点,做一些加加减减,在统计时直接计算前缀和就可以On的得到有效值,另外这题还要注意的就是取模和除以2时用逆元乘过去。


#include<cstring>#include<string>#include<iostream>#include<queue>#include<cstdio>#include<algorithm>#include<map>#include<cstdlib>#include<cmath>#include<vector>#include<time.h>//#pragma comment(linker, "/STACK:1024000000,1024000000");using namespace std;#define INF 0x3f3f3f3f#define maxn 2000002#define mod (1000000007)#define inv 500000004#define Mod(x) x=(((x)+mod)%mod)char Ma[maxn*2];int Mp[maxn*2];void Manacher(char s[],int len){    int l=0;    Ma[l++]='$';    Ma[l++]='#';    for(int i=0; i<len; i++)    {        Ma[l++]=s[i];        Ma[l++]='#';    }    Ma[l]=0;    int 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;        }    }}int len;char s[maxn];long long L[maxn],R[maxn];long long Lc[2][maxn],Rc[2][maxn];void init(){    memset(Lc,0,sizeof Lc);    memset(Rc,0,sizeof Rc);}void update1(int mid,int r,int val){    Lc[0][mid]+=val;    Lc[0][mid+r+2]-=val;    Lc[1][mid]+=1;    Lc[1][mid+r+2]-=1;    Rc[0][mid-r-2]-=val;    Rc[0][mid]+=val;    Rc[1][mid-r-2]-=1;    Rc[1][mid]+=1;}void solveOdd(){    long long sum=0,k=0;    for(int i=2; i<=2*len; i+=2)    {        sum+=2ll*Lc[0][i];Mod(sum);        k+=Lc[1][i];Mod(k);        L[i]=(sum-k*(i/2)+mod)%mod;        Mod(L[i]);    }    sum=0,k=0;    for(int i=2*len; i>=2; i-=2)    {        sum+=2ll*Rc[0][i];Mod(sum);        k+=Rc[1][i];Mod(k);        R[i]=((sum-k*(i/2))+mod)%mod;        Mod(R[i]);    }}void update2(int mid,int r,int val){    Lc[0][mid]+=val;    Lc[0][mid+r]-=val;    Lc[1][mid]+=1;    Lc[1][mid+r]-=1;    Rc[0][mid-r]-=val;    Rc[0][mid]+=val;    Rc[1][mid-r]-=1;    Rc[1][mid]+=1;}void solveEven(){    long long sum=0,k=0;    for(int i=2; i<=2*len; i++)    {        sum+=2ll*Lc[0][i];Mod(sum);        k+=Lc[1][i];Mod(k);        L[i]+=((((sum-k*i)+mod)%mod)*inv)%mod;        Mod(L[i]);    }    sum=0,k=0;    for(int i=2*len; i>=2; i--)    {        sum+=2ll*Rc[0][i];Mod(sum);        k+=Rc[1][i];Mod(k);        R[i]+=((((sum-k*i)+mod)%mod)*inv)%mod;        Mod(R[i]);    }}int main(){    while(scanf("%s",s)!=EOF)    {        memset(L,0,sizeof L);        memset(R,0,sizeof R);        len=strlen(s);        Manacher(s,len);        init();        for(int i=2; i<=2*len; i+=2)        {            int r=(Mp[i]/2-1)*2;            update1(i,r,i/2);        }        solveOdd();        init();        for(int i=3; i<=2*len-1; i+=2)        {            int r=Mp[i]-1;            update2(i,r,i);        }        solveEven();        long long ans=0;        for(int i=2; i<len*2; i+=2)        {            ans+=(L[i]*R[i+2])%mod;            Mod(ans);        }        printf("%lld\n",ans);    }    return 0;}






0 0
原创粉丝点击