P3649 [APIO2014]回文串(PAM记录不同回文出现次数)

LINK

板子题

每次插入我们可以找到这个点的最长后缀回文,那么这个回文 u u u不仅可以作用于 u u u

还让 f a i l [ u ] , f a i l [ f a i l [ u ] ] , f a i l [ f a i l [ f a i l [ u ] ] ] . . . . . fail[u],fail[fail[u]],fail[fail[fail[u]]]..... fail[u],fail[fail[u]],fail[fail[fail[u]]].....出现次数都加一

暴力跳 f a i l fail fail显然超时,所以我们只把贡献暂时挂在最长后缀这里

因为 f a i l [ u ] fail[u] fail[u]的索引一定小于 u u u

所以我们可以倒序枚举,给前面的加贡献,算当前的答案…

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 5e5+10;
int n; 
char a[maxn];
struct PAM
{
	int len[maxn],fail[maxn],zi[maxn][26],id,las,cnt[maxn];
	PAM()
	{
		id = las = 1;
		fail[0] = 1,fail[1] = 1,len[0] = 0,len[1] = -1;
	}
	int get_fail(int u,int index)
	{
		while( a[index]!=a[index-len[u]-1] )	u = fail[u];
		return u; 
	}
	void insert(int c,int index)
	{
		int u = get_fail(las,index);
		if( !zi[u][c] )
		{
			int now = ++id, v = get_fail( fail[u],index );
			fail[now] = zi[v][c], len[now] = len[u]+2;
			zi[u][c] = now;
		}
		las = zi[u][c]; cnt[las]++;
	}
	void build()
	{
		int n = strlen( a+1 ); 
		for(int i=1;i<=n;i++)	insert( a[i]-'a'+1,i );	
		int ans = 0;
		for(int i=id;i>=2;i--)
			cnt[fail[i]] += cnt[i];
		for(int i=2;i<=id;i++)
			ans = max( ans,len[i]*cnt[i] );
		cout << ans;
	}
}pam;
signed main()
{
	cin >> ( a+1 );
	pam.build(); 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值