Codeforces 159D. Palindrome pairs (Manacher +DP)

12 篇文章 0 订阅
10 篇文章 0 订阅

Description
You are given a non-empty string s consisting of lowercase letters. Find the number of pairs of non-overlapping palindromic substrings of this string.
In a more formal way, you have to find the quantity of tuples (a, b, x, y) such that 1 ≤ a ≤ b < x ≤ y ≤ |s| and substrings s[a… b], s[x… y] are palindromes.
A palindrome is a string that can be read the same way from left to right and from right to left. For example, “abacaba”, “z”, “abba” are palindromes.
A substring s[i… j] (1 ≤ i ≤ j ≤ |s|) of string s = s 1 s 2 . . . s ∣ s ∣ s = s_1 s_2... s_|s| s=s1s2...ss is a string s i s i   +   1 . . . s j s_i s_{i + 1}... s_j sisi+1...sj. For example, substring s [ 2...4 ] s[2...4] s[2...4] of string s = “abacaba” equals “bac”.

Input
The first line of input contains a non-empty string s which consists of lowercase letters (‘a’…‘z’), s contains at most 2000 characters.

Output
Output a single number — the quantity of pairs of non-overlapping palindromic substrings of s.

Please do not use the %lld format specifier to read or write 64-bit integers in С++. It is preferred to use cin, cout streams or the %I64d format specifier.

Examples
Input
aa
Output
1

Input
aaa
Output
5

Input
abacaba
Output
36

Main idea & Solution
给你一个串,让你找出有多少对不相交的子串s1,s2,满足s1 和 s2 都是回文串
注意到对于当前回文串 { l , r } \left\{l,r\right\} {l,r}, [ 1 , l − 1 ] [1, l - 1] [1,l1] 以内的所有回文串都可以和它组成合法答案
我们先用Manacher预处理,再计算 d p [ i ] dp[i] dp[i] : 以 i i i 为结尾的回文子串数,并计算该数组的前缀和
最后枚举计算答案即可

Code

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int maxn = 2e3 + 5;
char s[maxn];
int p[maxn*2];
char Ma[maxn*2];
void Manacher(int len){
	int l = 0;
	Ma[l++] = '$';Ma[l++] = '#';
	for(int i = 0;i < len;++i){
		Ma[l++] = s[i];
		Ma[l++] = '#';
	}
	Ma[l] = 0;
	int mx = 0, id = 0;
	for(int i = 0;i < l;++i){
		p[i] = mx > i ? min(p[id*2-i],mx-i) : 1;
		while(Ma[i+p[i]] == Ma[i-p[i]]) p[i]++;
		if(i + p[i] > mx){
			mx = i + p[i];
			id = i;
		}
	}
}
int dp[maxn*2];
int main(){
	ll res = 0;
	scanf("%s",s);
	int n = strlen(s);
	Manacher(n);
	for(int i = 1;i <= 2 * n;++i){
		int d = p[i];
		for(int j = 0 + (i&1);j < d;j+=2){
			dp[i+j]++;
		}
	}
	dp[0] = 0;
	for(int i = 1;i <= 2 * n;++i){
		dp[i] += dp[i-1];
	}
	for(int i = 1;i <= 2 * n;++i){
		int d = p[i];
		for(int j = 0 + (i&1);j < d;j+=2){
			res += dp[i-j-1];
		}
	}

	printf("%lld\n", res);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值