HDU6230-Palindrome (马拉车 +BIT )

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/kidsummer/article/details/82083413

题意描述

给定一个字符串,统计有多少个子串是one−and−half palindromicone−and−half palindromic. (即字符串长度为3n−23n−2,且满足S[i]=S[2n−i]=S[2n+i−2](1≤i≤n)S[i]=S[2n−i]=S[2n+i−2](1≤i≤n)。 
数据范围:字符串长度小于等于500000500000.

思路:

这个题目说了,所有的回文串都是奇数个,所以,我们已经不需要在添加字符了。直接在原串中用马拉车。

马拉车为什么要添加字符。就是为了要把回文串变成奇数个。

-----i----j------

要满足题目中的条件。我们就要找两个回文串,他们的回文长度相交就行。

这里,我的p[i]代表 i 的一半回文长度,包含 i ,就是总长度+1 / 2;

满足题目的长度,我们要满足以下条件。

1、 i < j

2、 i > j - p[j]

3、 j < i + p[i]

我们先做一遍 马拉车,找到了 p[i], 然后根据 第 2 条。找 j - p[j] < i 的数。我们先按 j - p[j] 从小到大排序,

吧 j - p[j] 的数的位置 j 插入到树状数组中去。然后找  i+1 ~ i + p[j]-1  这个区间的 j 有多少个。

#include <bits/stdc++.h>
#define mem(x,v) memset(x,v,sizeof(x)) 
#define go(i,a,b)  for (int i = a; i <= b; i++)
#define og(i,a,b)  for (int i = a; i >= b; i--)
#define low(x) (x & (-x))
#define X first
#define Y second
using namespace std;
typedef long long LL;
typedef pair<int,int> P;
const double EPS = 1e-10;
const int INF = 0x3f3f3f3f;
const int N = 6e5+10;
char t[N];
int len,p[N],c[N];
void Add(int x){
	while(x <= len) c[x]++,x += low(x);
}
LL Query(int x){
	LL ans = 0;
	while(x > 0) ans += c[x], x -= low(x);
	return ans;
}
void Manacher(){
	scanf("%s",t+1);
	len = strlen(t+1);
	int id = 0,mx = 0;
	for (int i = 1; i <= len; i++){
		p[i] = mx > i?min(p[2*id-i],mx-i):1;
		while(t[i-p[i]] == t[i+p[i]]) p[i]++;
		if (mx < i+ p[i]){
			id = i;
			mx = i + p[i];
		}
	}
	return;
}

int main(){
	int T; cin>>T;
	while(T--){
		mem(c,0);
		mem(p,0);
		Manacher();
		priority_queue<P,vector<P>,greater<P> >Q;
		go(i,1,len) Q.push(P(i-p[i],i));
		LL sum = 0;
		go(i,1,len){
			while(!Q.empty() && Q.top().X < i){
				P u = Q.top(); Q.pop();
				Add(u.Y);
			}
			sum += (Query(i+p[i]-1)-Query(i));
		}
		printf("%I64d\n",sum);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/kidsummer/article/details/82083413