2017 CCPC哈尔滨站 Palindrome (马拉车+树状数组)

题目定义了 “一个半回文串”,其实就是形如abab,是一个长度3n-2的字符串,其中子串[1,2n-1]是长度为奇数的回文串,[n,3n-2]同样是长度为奇数的回文串。

那么所求可转化如下。

首先,因为回文串长度均为奇数,因此我们不需要考虑偶数长度的回文子串。

假设位置i的字符作为回文子串的中心时的最大回文半径为r[i](这个显然可以通过马拉车算法预处理出),则我们要求的是这样的 (i,j)的对数:

假设i>j,则有 i-r[i]>=j && j+r[j]>=i,因为只有这样的一对位置,才可以保证能形成符合要求的“一个半回文串”。

这个感觉很像是一个二维偏序问题。

对所有的(i-r[i],i)按i-r[i]从小到大排序,从小到大枚举j,因为只有i-r[i]小于等于当前j的i才可能与之形成符合要求的 (i,j),因此将所有i-r[i]小于等于当前j的i插入树状数组(即将对应位置+1),然后,统计在(j,j+r[j]]之间的和即可。

代码:

#include
using namespace std;
#define mst(a,b) memset(a,b,sizeof(a))
#define ll long long
const int MAXN=5e5+5;
char Ma[MAXN];
int Mp[MAXN];
void Manacher(char s[],int len){
//因为只需要求奇数长度的回文串,所以除了起始字符外不用添加特殊字符 
	int l=len+1;
	Ma[0]='$';
	Ma[l]=0;
	int mx=0,id=0;
	for(int i=0;ii?min(Mp[2*id-i],mx-i):1;
		while(Ma[i+Mp[i]]==Ma[i-Mp[i]]) Mp[i]++;
		if(i+Mp[i]>mx){
			mx=i+Mp[i];
			id=i;
		}
	}
}
int t;
int c[MAXN];
int lowbit(int x){
	return x&(-x);
}
void add(int x,int z=1){
	while(x0){
		res+=c[x];
		x-=lowbit(x);
	}
	return res;
}
struct node{
	int d,pos; 
	bool operator<(const node &p)const{//按差值排序 
		return d=1;i--){ 
			a[cnt].d=i-Mp[i];
			a[cnt].pos=i;
			cnt++;
		}
		sort(a,a+cnt);
		for(int i=1,j=0;i

 

你可能感兴趣的:(字符串)