【杭电多校2020】Minimum Index【Lyndon Word】

本文深入解析Duval算法,一种用于求解字符串所有前缀最小后缀的高效算法,适用于n≤2×10^7的大规模数据处理。通过实例演示算法流程,包括循环节维护、LyndonWord判断等关键步骤,最终实现O(n)时间复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:给定字符串,求所有前缀的最小后缀。

n≤2×107n\leq 2\times10^7n2×107

最小后缀就是Lyndon分解的最后一段。而Duval本质上是可以重复修改的增量算法,所以是可以做的。

ansians_iansi为前缀iii的最小后缀。设维护未确定的循环节的指针为i,j,ki,j,ki,j,k,即Si...k−1=t+t+...+t+t1S_{i...k-1}=t+t+...+t+t_1Si...k1=t+t+...+t+t1,其中ttt为Lyndon Word,t1t_1t1为其可空前缀,j=k−∣t∣j=k-|t|j=kt

Sj=SkS_j=S_kSj=Sk时,根据意识流,前缀jjj的最小后缀一定在[i,j][i,j][i,j]内。因为是个循环,所以ansk=ansj+k−jans_k=ans_j+k-jansk=ansj+kj

Sj<SkS_j<S_kSj<Sk,令j=ij=ij=i,此时Sj...kS_{j...k}Sj...k是个Lyndon Word,所以ansk=jans_k=jansk=j

Sj>SkS_j>S_kSj>Sk,相当于t1t_1t1这一段的ansansans都是假的,需要重新计算,不用管。但∣t1∣=1|t_1|=1t1=1的时候会出一些奇怪的问题,需要把anskans_kansk的值算出来,为iiikkk

复杂度O(n)O(n)O(n)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cctype>
#define MAXN 20000005
using namespace std;
char s[MAXN];
int ans[MAXN];
const int MOD=1e9+7;
int main()
{
	int T;
	scanf("%d",&T);
	while (T--)
	{
		scanf("%s",s+1);
		int n=strlen(s+1);
		for (int i=1;i<=n;i++) ans[i]=0;
		ans[1]=1;
		for (int i=1;i<=n;)
		{
			int j=i,k=i+1;
			ans[k]=k;
			while (s[j]<=s[k])
			{
				if (s[j]==s[k]) ans[k]=ans[j]+k-j,++j;
				else ans[k]=j=i;
				++k;
			}
			while (i<=j) i+=k-j;
			ans[k]=i;
		}
//		for (int i=1;i<=n;i++) printf("%d%c",ans[i]," \n"[i==n]);
		int sum=0;
		for (int i=1,x=1;i<=n;i++,x=x*1112ll%MOD) sum=(sum+1ll*ans[i]*x)%MOD;
		printf("%d\n",sum);
	}
	return 0;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值