HDU-5785 Manacher+区间处理

Interesting

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


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


题目链接:

题目大意:
给出一个长度为n(n<=10^6)的串,对于0<i<=j<k<=n,如果s[i,j]和s[j+1,k]都是回文串,则答案加上i*k,最后答案模10^9+7。

解题思路:
在原串上,用L[i]表示以i开始的所有回文串结束位置的和,R[i]表示以i结尾的所有回文串起始位置的和,枚举位置i,每次将L[i]*R[i-1]加上答案即可。
如何得到数组L[i]与R[i]呢,首先用Manacher预处理出以每个位置为中心的回文串的半径,我们发现对于每个位置i,它前面半径内的每个位置j对应的以i为中心的回文串的结束位置在新串中为i*2-j,我们要将这个值加到L上。这里可以采用树状数组的思想,把这个值分为两部分i*2与j,用数组p[i]表示半径,bb1、bb2代表两个标记,每次枚举i,我们只需要bb1[i-p[i]+1]+=i,bb2[i-p[i]+1]++,bb1[i+1]-=i,bb2[i+1]--即可。我们从前往后扫一遍,将bb1与bb2的值分别加到两个和s1与s2中,这样在每个位置s1就代表了上面那个值的第一部分,s2代表了在该位置j处需要减去j的次数。我们的L是定义在原串上的,由于新串在原串相邻字符间插入了'#',所以在计算原串L的时候s1不需要再*2,并且奇偶的情况也得到了统一,于是对于新串上每个偶数位置i对应原串L[i/2]=s1-s2*i/2。同理,可以计算出数组R,总体复杂度为O(n)。

AC代码:
import java.io.*;
import java.util.*;

public class Main {
	static StreamTokenizer in=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
	static PrintWriter out=new PrintWriter(new OutputStreamWriter(System.out));
	static int n,len;
	static long ans,mod=(long)1e9+7,s1,s2;
	static char[] ss;
	static int[] pp=new int[2000005];
	static char[] s=new char[2000005];
	static long[] bb1=new long[2000005];
	static long[] bb2=new long[2000005];
	static long[] ll=new long[1000005];
	static long[] rr=new long[1000005];
	static void Manacher()
	{
		Arrays.fill(s,'#');
		for(int i=0;i<n;i++)
			s[i*2+2]=ss[i];
		len=n*2+1;s[0]='$';
		int max=0,id=0;
		for(int i=1;i<=len;i++)
		{
			if(max>i)
				pp[i]=Math.min(pp[id*2-i],max-i);
			else pp[i]=1;
			while(s[i+pp[i]]==s[i-pp[i]])
				pp[i]++;
			if(i+pp[i]>max) { max=i+pp[i];id=i;}
		}
	}

	public static void main(String[] args) throws IOException {
		//Scanner in=new Scanner(System.in);
		while(in.nextToken()!=StreamTokenizer.TT_EOF)
		{
			ss=in.sval.toCharArray();
			n=ss.length;
			Manacher();
			Arrays.fill(bb1,0);
			Arrays.fill(bb2,0);
			for(int i=len;i>0;i--)
			{
				bb1[i-pp[i]+1]+=i;
				bb1[i+1]-=i;
				bb2[i-pp[i]+1]++;
				bb2[i+1]--;
			}
			s1=s2=0;
			for(int i=1;i<=len;i++)
			{
				s1+=bb1[i];s2+=bb2[i];
				if(i%2==0)
					ll[i/2]=(s1-s2*i/2)%mod;
			}
			Arrays.fill(bb1,0);
			Arrays.fill(bb2,0);
			for(int i=len;i>0;i--)
			{
				bb1[i]+=i;
				bb1[i+pp[i]]-=i;
				bb2[i]++;
				bb2[i+pp[i]]--;
			}
			s1=s2=0;
			for(int i=1;i<=len;i++)
			{
				s1+=bb1[i];s2+=bb2[i];
				if(i%2==0)
					rr[i/2]=(s1-s2*i/2)%mod;
			}
			ans=0;
			for(int i=2;i<=n;i++)
				ans=(ans+ll[i]*rr[i-1]%mod)%mod;
			out.println(ans);
		}
		out.flush();
	}
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值