HDU 5785 Interesting (manacher+区间处理)

Interesting

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

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   |   We have carefully selected several similar problems for you:  5803 5802 5801 5800 5799 

题意:有一个长度为n的串(n<=10^6),对 1 <= i <= j < k <= length(s) .  如果【i,j】和【j+1,k】都是回文串。则对答案的贡献为 i*k ,求贡献和。

题解
在O(n)时间内算出左右的回文个数。
用Manacher处理出每个字符的回文半径。如果用  L[i]  表示以 i 结尾的回文串的左端点坐标值之和, R[i] 表示以i开头的右端点的坐标值之和。那么显然答案就是  。接下来要求的就是L【i】R【i】。以 L[i] 为例,一个中心为 i 半径为 l 的回文串对属于【il+1,i】的 L [ i ] 值都是有贡献的,且对于  的贡献为  i +(i - j), 那么, 。
其中 j 是包含 i 的回文串的对称轴坐标,k是i被包含在回文串左半边的次数。
因为没有动态的修改,所以只要  O(n) 处理即可。 R[i] 同理。 
这题可以直接在Manacher处理的回文半径上直接计算,对于 ,  L[i]   的贡献为 
对于对称轴为#的情况同样适用。
因此, 。
在计算最后的答案时只要每次+=2就可以了。

注意:在manacher中串长是原串的2倍。
           如果有一个长串是回文串,那它的某一中心串也是回文串。

AC代码:
#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
const int maxn=1e7;
char str[maxn];
int n,L;
int p[maxn];
char s[maxn];
/*
data[1]表示以当前点为右边界的所有回文串的中心的和的两倍。
data[2]表示以当前点为右边界的所有回文串的个数。
data[3]表示以当前点为左边界的所有回文串的中心的和的两倍。
data[4]表示以当前点为左边界的所有回文串的个数。
*/
int data[5][2000100];
//manacher预处理 
void init()
{
	memset(data,0,sizeof(data));
	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; 
}
//manacher 
void manacher()
{
	int mx=0;
	int id;
	for(int i=1;i<L;i++)
	{
		if(mx>i)
		{
			p[i]=min(p[2*id-i],mx-i); //mx-i写成p[id]+id-i也行 
		}
		else p[i]=1;
		while(str[i+p[i]]==str[i-p[i]])  
            p[i]++;  
            
            if(p[i]+i>mx)  
      	   	{  
           	 	mx=p[i]+i;  
            	id=i;  
       	}  
	}
}
// 
void add(int op,int l,int r,int num)
{
    if (l>r) return ;
    data[op][l] += num;
    data[op][l] %= mod;

    data[op][r+1] -= num;
    data[op][r+1] %= mod;
}
int main()
{
	while(~scanf("%s",s))
	{
		init();
		manacher();
		for(int i=L-1;i>=1;--i) //右边 
		{
			add(1,i-p[i]+1,i,i); //data[1] 
			add(2,i-p[i]+1,i,1); //data[2] 
		}
		for (int i=1;i<L;i++)   //左边 
        {
            add(3,i,i+p[i]-1,i); //data[3] 
            add(4,i,i+p[i]-1,1);  //data[4] 
        }
        for (int i=1;i<L;i++)
        {
            for (int j=1;j<=4;j++)
            {
                data[j][i]+=data[j][i-1];
                data[j][i]=(mod+data[j][i])%mod;
            }
        }

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



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值