【BZOJ 3790】神奇项链 回文树+贪心

236 篇文章 0 订阅
5 篇文章 0 订阅

找出以每一个点作为尾端的最长区间然后就变成了一道很简单的区间完全覆盖问题,倒过来直接上贪心就好了,至于如何找最长区间需要用到回文树

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define maxn 50021
using namespace std;
int n,p,ch[maxn][26],fail[maxn],len[maxn],N,s[maxn];
int last,cnt;
char ss[maxn];
struct edge{
	int l,r;
	edge(int a=0,int b=0):l(a),r(b){}
}e[maxn];
int newnode(){
	memset(ch[p],0,sizeof(ch[p]));
	fail[p]=len[p]=0;
	return p++;
}
int get(int x){
	while(s[n]!=s[n-len[x]-1])x=fail[x];
	return x;
}
void insert(int c,int id){
	s[++n]=c;
	int cur=get(last);
	if(!ch[cur][c]){
		int now=newnode();
		fail[now]=ch[get(fail[cur])][c];
		len[now]=len[cur]+2;
		ch[cur][c]=now;
	}
	last=ch[cur][c];
	e[++cnt]=edge(n-len[last],id);
}
int main(){
	while(scanf("%s",ss)!=EOF){
		p=n=cnt=last=0,s[0]=-1;
		len[newnode()]=0;
		len[newnode()]=-1;
		fail[0]=1;
		
		N=strlen(ss);
		for(int i=0;i<N;i++)insert(ss[i]-'a',i);
		
		int ans=0,ml=N,now=N+1;
		for(int i=cnt;i>=1;i--){
			if(e[i].l<ml)ml=e[i].l;
			if(e[i].r<now)now=ml,ans++;
		}
		printf("%d\n",ans-1);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值