HDU 5785 interesting

给你一个字符串,问满足i<=j<k并且【i,j】和【j,k】都是回文的时候,i*k的sum值是多少。

看了网上的做法,基本都是每个点算贡献,但是有的记录起来比较考验代码能力。

其中有一种做法是这样的:

首先,推公式,自然不用说。由于每个i*k必然出现在一个以j为中心的双回文串中,所以直接统计左右以当前点和下一个点以左与以右的回文个数,相乘即可。

下面是在O(n)时间内算出左右的回文个数。

定义四个数组。

date[1]表示以当前点为右边界的所有回文串的中心的和的两倍。

date[2]表示以当前点为右边界的所有回文串的个数。

date[3]表示以当前点为左边界的所有回文串的中心的和的两倍。

date[4]表示以当前点为左边界的所有回文串的个数。

然后遍历,想到一个点的贡献自然是这个点向左回文范围内所有位置加一,右边也是。因为大的回文小的肯定回文。

在计算个数的时候,也要把区间内的数值都加上i(当前遍历的中心,因为在马拉车里,所以是二倍的中心),以备用。

然后就是核心计算部分了,这里是非常巧妙地地方。

由于要求统计以这个点为左端点的回文右端点,而我们统计的是二倍的中心,其实不难看出对于每一个右端点,要得到它,我们可以把中心加倍,然后减去当前这个值(左端点)就是右端点的所在位置。以此类推,可以求出另一半左端点的位置。

而有人会问怎么保证j<k而没有j=k的情况呢?那么就是关键。因为我在最后加的时候,直接用下一个位置加,以此保证两串不会重叠。

#include <cstdio>
#include <cstring>
#include <vector>
#include <cmath>
#include <stack>
#include <cstdlib>
#include <queue>
#include <map>
#include <iostream>
#include <algorithm>
#include <bits/stdc++.h>

using namespace std;
const int MAXN=((1e6)+5)*2;
char str[MAXN];
int p[MAXN];
int MOD=1e9+7;
char s[MAXN];
int n,L;
void manacher()
{
    int mx=0,id;
//    printf ("n=%d\n",n);
    for (int i=1;i<L;i++)//第一个是自己添加的,最后一个是1
    {
        if (mx>i)
            p[i]=min(p[2*id-i],p[id]+id-i);
        else
            p[i]=1;
        for (;str[i+p[i]]==str[i-p[i]];p[i]++)
        if (p[i]+i>mx)
        {
            mx=p[i]+i;
            id=i;
        }
    }
}
int date[5][2000100];//1是2倍右中心,2是右个数,3是2倍左中心,4是左个数
void init()
{
    memset(date,0,sizeof(date));
    int i,j,k;
    n=strlen(s);
    str[0]='@';
    str[1]='#';
    for (int i=0;i<n;i++)
    {
        str[i*2+2]=s[i];
        str[i*2+3]='#';
    }
    L=n*2+2;
    str[L]=0;
}
void add(int op,int l,int r,int num)
{
    if (l>r) return ;
    date[op][l]+=num;
    date[op][l]%=MOD;

    date[op][r+1]-=num;
    date[op][r+1]%=MOD;
}
int main()
{
    while (scanf ("%s",s)!=EOF)
    {
        init();
        manacher();
//        for (int i=1;i<L;i++)
//        {
//            printf ("%d ",p[i]);
//        }
//        printf ("\n");
        for (int i=L-1;i>=1;i--)
        {
            add(1,i-p[i]+1,i,i);
            add(2,i-p[i]+1,i,1);
        }
        for (int i=1;i<L;i++)
        {
            add(3,i,i+p[i]-1,i);
            add(4,i,i+p[i]-1,1);
        }
        for (int i=1;i<L;i++)
        {
            for (int j=1;j<=4;j++)
            {
                date[j][i]+=date[j][i-1];
                date[j][i]=(MOD+date[j][i])%MOD;
            }
        }

        int ans=0;
        for (int i=2;i<L-2;i+=2)
        {
            int aa,bb;
            aa=((date[1][i+2]-(long long)date[2][i+2]*((i+2)/2))%MOD+MOD)%MOD;
            bb=((date[3][i]-(long long)date[4][i]*(i/2))%MOD+MOD)%MOD;
            ans+=((long long)aa*(long long)bb)%MOD;
            printf ("i=%d\n",i/2);
            printf ("%lld\n",((long long)aa*(long long)bb)%MOD);
            ans%=MOD;
        }
        printf ("%d\n",ans);
    }
    return 0;
}

 

posted on 2016-08-03 21:10  very_czy  阅读(191)  评论(0编辑  收藏  举报

导航