HDU_5785_Interesting(回文树||manacher)

Interesting

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 336    Accepted Submission(s): 117


Problem Description
Alice get a string S. She thinks palindrome string is interesting. Now she wanna know how many three tuple (i,j,k) satisfy 1ij<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
  
  
aaa abc
 

Sample Output
  
  
14 8
 

Author
ZSTU
 

Source
 

Recommend
wange2014


题意

给你一个串

定义了一个权值和

每个权值是两个回文串拼起来的左右坐标乘积


做法

一看回文,果断上回文树

由于要两个回文串拼起来,于是想到最长双回文串那个题目

把串正着扫一遍反着扫一遍就可以得到所有的双回文串

这道题目,我在回文树里多维护了,每个节点为结尾位置的所有回文串的长度和

由于num数组有以此为结尾的长度数量,因此可以通过这两个算出以某点结尾的所有回文串起始坐标的和

同理也可算出所有以某点开始的所有回文串结尾坐标的和

于是把这两个分别乘起来加和即可。


不过这个题目用回文树有爆空间的危险,各个细节必须处理的很好才行。中间过程开LL结果保存先取模再存回int

标答用的manacher也可以做类似的维护来算出结果


#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
typedef long long LL;
const int MAXN=1e6+5;
const int MO=1e9+7;
const int N=26;
int l[MAXN],l1[MAXN];

struct Palindromic_Tree {
    int next[MAXN][N];
    int fail[MAXN],len[MAXN],num[MAXN];
    char S[MAXN];
    int n,p,last;
    int newnode(int l)
    {
        for(int i = 0; i < N; ++i) next[p][i] = 0;
        num[p] = 0;
        len[p] = l;
        return p++;
    }
    void init()
    {
        last = n = p = 0;
        newnode(0);
        newnode(-1);
        S[0] = -1;
        fail[0] = 1;
        fail[1] = 0;
        l[0]=0;
        l[1]=0;
    }
    int get_fail(int x)
    {
        while(S[n-len[x]-1]!=S[n])
            x=fail[x];
        return x;
    }
    int add(int c) ///返回新添加的节点
    {
        c -= 'a';
        S[++n] = c;
        int cur = get_fail(last);
        if(!next[cur][c]) {
            int now = newnode(len[cur]+2);
            fail[now] = next[get_fail(fail[cur])][c];
            //if(fail[now]==0)
            //    l[now]=1;
            //else
            l[now]=((LL)l[fail[now]]+len[now])%MO;
            next[cur][c] = now;
            num[now]=num[fail[now]]+1;
        }
        last = next[cur][c];
        return last;
    }
};
Palindromic_Tree T;
char s[MAXN];
int main()
{
    while(scanf("%s",s+1)!=EOF)
    {
        memset(l,0,sizeof(l));
        T.init();
        int n=strlen(s+1);
        for(int i=n;i>=1;--i)
        {
            int tmp=T.add(s[i]);
            //cout<<"l  "<<l[tmp]<<" num "<<T.num[tmp]<<endl;
            l1[i]=(l[tmp]+(LL)(i-1)*T.num[tmp])%MO;
        }
        //for(int i=1;i<=n;i++)
        //    cout<<l1[i]<<" ";
        //cout<<endl;
        //memccpy(l1,l,sizeof(l));
        LL ans=0;
        T.init();
        memset(l,0,sizeof(l));
        for(int i=1;i<n;++i)
        {
            int tmp=T.add(s[i]);
            //cout<<"l  "<<l[tmp]<<" num "<<T.num[tmp]<<" "<<(T.num[tmp]*(i+1)-l[tmp])<<endl;
            ans=(ans+(((LL)T.num[tmp]*(i+1)-l[tmp])%MO)*l1[i+1]%MO)%MO;
        }
        printf("%I64d\n",ans);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值