HDU5785 Interesting(回文串&&前缀和)

该博客介绍了如何使用Manacher算法解决HDU5785题目的回文串问题。博主详细阐述了题意,并解析了思路,即通过考虑回文串的区间特性来优化求解过程,最后给出了解决问题的代码实现。

题目:

http://acm.hdu.edu.cn/showproblem.php?pid=5787

题意:

找出所有相邻的回文串,将它们最外侧的端点坐标乘积都加起来,(i,j),(j+1,k) 两个回文串,将所有的i*k加和。

思路:

回文串直接用Manacher求解,然后对于所有的回文串都包含许多小的回文串,例如(i,j)回文串同时代表(i+1,j-1)等许多回文串,所以需要将更新的值看为一个区间,然后将所有区间求和,分别处理每个点作为回文串左右端点的情况,最后乘积求和即可。

代码:

//kopyh
#include <bits/stdc++.h>
#define MOD 1000000007
#define N 2000005
using namespace std;
int n,m,sum,res,flag,tot;
int p[N*2];
int Manacher(char *str)
{
    int res=0,ans=0,len=strlen(str);
    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++)
    {
        if(p[res]+res > i)
            p[i] = min(p[2*res-i],p[res]+res-i);
        else
            p[i] = 1;
        while(str[i-p[i]] == str[i+p[i]])
            p[i]++;
        if(res+p[res]<i+p[i])res=i;
        if(ans<p[i])ans=p[i];
    }
    return ans-1;
}
char s[N];
long long a1[N],a2[N],b1[N],b2[N],aa[N],bb[N],ta[N],tb[N];
int main()
{
    int i,j,k,cas,T,t,x,y,z;
    while(scanf("%s",s)!=EOF)
    {
        n=strlen(s);
        Manacher(s);
        m=strlen(s);
        sum=0;tot=0;
        memset(a1,0,sizeof(a1));
        memset(b1,0,sizeof(b1));
        memset(a2,0,sizeof(a2));
        memset(b2,0,sizeof(b2));
        memset(ta,0,sizeof(ta));
        memset(tb,0,sizeof(tb));
        for(i=2;i<m-1;i++)
        {
            t=p[i]-1;
            y=i+t;if(y&1)y--;
            x=i-t;if(x&1)x++;
            x/=2;y/=2;
            int mm=(x+y+1)/2;
            a1[mm]+=(y-x)&1?mm-1:mm; a1[mm]%=MOD; ta[mm]++;
            a2[y]+=x; a2[y]%=MOD; ta[y]--;
            mm = (x+y)/2;
            b1[x]+=y; b1[x]%=MOD; tb[x]++;
            b2[mm]+=(y-x)&1?mm+1:mm; b2[mm]%=MOD; tb[mm]--;
        }
        long long x=0,y=0,z=0;
        for(i=1,j=0;i<=n;i++)
        {
            x-=y; x+=MOD; x%=MOD;
            x+=a1[i]; aa[i]=x;
            x-=a2[i]; y+=ta[i];
        }
        x=0,y=0,z=0;
        for(i=1,j=0;i<=n;i++)
        {
            x-=y; x+=MOD; x%=MOD;
            x+=b1[i]; bb[i]=x;
            x-=b2[i]; y+=tb[i];
        }
        long long res=0;
        for(i=2;i<=n;i++)
            res = (res+aa[i-1]*bb[i])%MOD;
        printf("%I64d\n",res%MOD);
    }
    return 0;
}








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值