【BZOJ2342】【SHOI2011】双倍回文

【题目链接】

【思路要点】

  • 补档博客,无题解。

【代码】

//PalindromicTree
#include<bits/stdc++.h>
using namespace std;
#define MAXN	500005
int n; char s[MAXN];
struct Palindromic_Tree {
	int child[MAXN][26], ans;
	int father[MAXN], depth[MAXN];
	int last, size;
	vector <int> a[MAXN];
	bool mark[MAXN];
	int new_node(int length) {
		memset(child[size], 0, sizeof(child[size]));
		father[size] = 0;
		depth[size] = length;
		return size++;
	}
	void Extend(int ch, int pos) {
		int p = last;
		while (s[pos - depth[p] - 1] != s[pos])
			p = father[p];
		if (!child[p][ch]) {
			int now = new_node(depth[p] + 2), q = father[p];
			child[p][ch] = now;
			while (s[pos - depth[q] - 1] != s[pos])
				q = father[q];
			if (p == 0 || child[q][ch] == 0) father[now] = 1;
			else father[now] = child[q][ch];
		}
		last = child[p][ch];
	}
	void init() {
		size = 0;
		new_node(-1);
		new_node(0);
		father[1] = 0;
		last = 0;
		for (int i = 1; i <= n; i++)
			Extend(s[i] - 'a', i);
	}
	void work(int pos) {
		mark[depth[pos]] = true;
		if (depth[pos] % 4 == 0 && mark[depth[pos] / 2]) ans = max(ans, depth[pos]);
		for (unsigned i = 0; i < a[pos].size(); i++)
			work(a[pos][i]);
		mark[depth[pos]] = false;
	}
	int getans() {
		ans = 0;
		for (int i = 2; i < size; i++)
			a[father[i]].push_back(i);
		memset(mark, false, sizeof(mark));
		work(1);
		return ans;
	}
} PT;
int main() {
	scanf("%d\n%s", &n, s + 1);
	PT.init();
	printf("%d\n", PT.getans());
	return 0;
}
//Manacher + SegmentTree
#include<bits/stdc++.h>
using namespace std;
#define MAXN	1000005
struct SegMentTree {
	struct Node {
		int lc,rc;
		int maxnum;
	};
	Node a[MAXN*2];
	int size,n;
	private:
		void build(int now,int l,int r) {
			a[now].maxnum=0;
			if (l==r) return;
			int mid=(l+r)/2;
			a[now].lc=++size;
			build(size,l,mid);
			a[now].rc=++size;
			build(size,mid+1,r);
		}
		void update(int now) {
			if (a[now].lc==0) return;
			a[now].maxnum=max(a[a[now].lc].maxnum,a[a[now].rc].maxnum);
		}
		void maintain(int now,int l,int r,int x,int value) {
			if (l==r) {
				a[now].maxnum=value;
				return;
			}
			int mid=(l+r)/2;
			if (mid>=x) maintain(a[now].lc,l,mid,x,value);
			else maintain(a[now].rc,mid+1,r,x,value);
			update(now);
		}
		int query(int now,int l,int r,int ql,int qr) {
			if (l==ql && r==qr) return a[now].maxnum;
			int ans=0,mid=(l+r)/2;
			if (mid>=ql) ans=max(ans,query(a[now].lc,l,mid,ql,min(mid,qr)));
			if (mid+1<=qr) ans=max(ans,query(a[now].rc,mid+1,r,max(mid+1,ql),qr));
			return ans;
		}
	public:
		void init(int x) {
			n=x;size=0;
			build(size,0,n);
		}
		void modify(int pos,int value) {
			maintain(0,0,n,pos/2,value);
		}
		int ask(int l,int r) {
			return query(0,0,n,l/2,r/2);
		}
};
struct info {bool type;int value;};
char s[MAXN],x[MAXN];
int len[MAXN];
vector <info> operation[MAXN];
SegMentTree T;
int main() {
	int n;
	scanf("%d",&n);
	scanf("\n%s",s+1);
	x[0]='$';x[1]='#';x[2*n+2]='%';
	for (int i=1;i<=n;i++)
		{x[i*2]=s[i];x[i*2+1]='#';}
	int pos=0,r=0;
	for (int i=1;i<=2*n+1;i++) {
		if (i<=r) {
			int j=pos*2-i;
			if (len[j]<r-i+1) len[i]=len[j];
			else {
				len[i]=r-i+1;
				while (x[i+len[i]]==x[i-len[i]]) len[i]++;
				pos=i;r=i+len[i]-1;
			}
		}
		else {
			len[i]=1;
			while (x[i+len[i]]==x[i-len[i]]) len[i]++;
			pos=i;r=i+len[i]-1;
		}
	}
	for (int i=0;i<=n;i++) {
		operation[2*i+1-len[2*i+1]+1].push_back((info){true,2*i+1});
		operation[2*i+1].push_back((info){false,2*i+1});
	}
	int ans=0;
	T.init(n);
	for (int i=0;i<=n;i++) {
		for (int j=0;j<operation[i*2+1].size();j++)
			if (operation[i*2+1][j].type) T.modify(operation[i*2+1][j].value,operation[i*2+1][j].value);
			else T.modify(operation[i*2+1][j].value,0);
		int tmp=T.ask(i*2+1,i*2+len[i*2+1]/2);
		ans=max(ans,(tmp-(i*2+1))/2);
	}
	printf("%d\n",ans*4);
			 
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值