hdu5785Interesting

链接:http://acm.hdu.edu.cn/showproblem.php?pid=5785

题意:给定一个字符串s,对于每一个1<=i<=j<k<=len的情况如果s[i]~s[j]和s[j+1]~s[k]都是回文串的话统计i*k给ans,求ans。

分析:很明我们不能枚举3个量,但是我们还是得确定位置,那么我们枚举j,我们用manacher预处理出回文串,统计出每个位置w,以w为第一个字符和最后一个字符的回文串的信息,以w为第一个字符的回文串的所有的k的和,以w为最后一个字符的回文串的所有的i的和,那么统计所有的suf[w]*pre[w+1]即可。O(n)

代码:

#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<bitset>
#include<math.h>
#include<vector>
#include<string>
#include<stdio.h>
#include<cstring>
#include<iostream>
#include<algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int N=1000010;
const int mod=100000000;
const int MOD1=1000000007;
const int MOD2=1000000009;
const double EPS=0.00000001;
typedef long long ll;
const ll MOD=1000000007;
const int INF=1000000010;
const ll MAX=1ll<<55;
const double pi=acos(-1.0);
typedef double db;
typedef unsigned long long ull;
char s[2*N];
int p_ma[2*N];
void Manacher(char s[],int les) {
    int i,mx,id;
    for (i=les-1;i>=0;i--) {
        s[2*i+2]=s[i];s[2*i+3]='#';
    }
    mx=id=0;s[1]=s[2*les+2]='#';les=les<<1|1;
    for (i=1;i<=les;i++) {
        if (mx>i) p_ma[i]=min(p_ma[2*id-i],mx-i);
        else p_ma[i]=1;
        for (;i-p_ma[i]>0&&s[i-p_ma[i]]==s[i+p_ma[i]];p_ma[i]++);
        if (i+p_ma[i]>mx) mx=i+p_ma[i],id=i;
    }
}
int g[N],pre[N],suf[N];
int main()
{
    int i,len;
    ll ans;
    while (scanf("%s", s)!=EOF) {
        len=strlen(s);
        Manacher(s,len);
        for (i=1;i<=len;i++) g[i]=suf[i]=0;
        for (i=2;i<=2*len;i++)
        if (i&1) {
            g[i/2+p_ma[i]/2]++;g[i/2]--;
            suf[i/2+p_ma[i]/2]=(suf[i/2+p_ma[i]/2]+i/2-p_ma[i]/2+1)%MOD;
            suf[i/2]=(suf[i/2]-i/2-1)%MOD;
        } else {
            g[i/2+p_ma[i]/2-1]++;g[i/2-1]--;
            suf[i/2+p_ma[i]/2-1]=(suf[i/2+p_ma[i]/2-1]+i/2-p_ma[i]/2+1)%MOD;
            suf[i/2-1]=(suf[i/2-1]-i/2-1)%MOD;
        }
        for (i=len-1;i;i--) suf[i]=(suf[i]+suf[i+1]+g[i+1])%MOD,g[i]+=g[i+1];

        for (i=1;i<=len;i++) g[i]=pre[i]=0;
        for (i=2;i<=2*len;i++)
        if (i&1) {
            g[i/2-p_ma[i]/2+1]++;g[i/2+1]--;
            pre[i/2-p_ma[i]/2+1]=(pre[i/2-p_ma[i]/2+1]+i/2+p_ma[i]/2)%MOD;
            pre[i/2+1]=(pre[i/2+1]-i/2)%MOD;
        } else {
            g[i/2-p_ma[i]/2+1]++;g[i/2+1]--;
            pre[i/2-p_ma[i]/2+1]=(pre[i/2-p_ma[i]/2+1]+i/2+p_ma[i]/2-1)%MOD;
            pre[i/2+1]=(pre[i/2+1]-i/2+1)%MOD;
        }
        for (i=2;i<=len;i++) pre[i]=(pre[i]+pre[i-1]-g[i-1])%MOD,g[i]+=g[i-1];

        for (ans=0,i=1;i<len;i++) ans=(ans+(ll)suf[i]*pre[i+1])%MOD;
        printf("%I64d\n", (ans+MOD)%MOD);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值