杭电多校2020第一场

1011-Minimum Index

题意:
遍历字符串,求所有前缀的最小后缀,最后求和。

题解:
这题使用到Lyndon Word的知识,🖱️
对于字符串 𝑆,若 𝑆 的最小后缀为其本身,那么称 𝑆 为 Lyndon 串(Lyndon Word),
任意字符串都可以分解成S=t1t2t3…tk,t表示已经确定的Lyndon串,该分解是唯一的,并且有ti<=ti+1的性质。

用三个循环变量 𝑖,𝑗,𝑘 维持一个循环不变式:

·S[1…𝑖−1]=S1S2⋯S𝑔 是已经固定下来的分解,满足 S𝑙 是 Lyndon 串,且 S𝑙≤S𝑙+1
·𝑗−𝑖是当前最长的 Lyndon prefix 的长度,即 S[𝑗] 是 S[𝑘] 在 Lyndon Prefix 中对应位置的字符。
·𝑘是当前读入的字符的位置。

那么,
当Sj = Sk时,有 ans[k] = ans[j] + j - k;
当Sj < Sk时,此时Sik 是一个Lyndon串,j还原到i继续执行相同的步骤;
当Sj > Sk 时,则递归求解,先分解完 S[𝑖…𝑡] ,然后将指针指向 𝑡+1 重新进行算法过程。

复杂度为O(n)。

AC_CODE:

const int maxn = 4e6+5;
char s[maxn];
int lyndon[maxn];
ll ans[maxn];
int N;

void Lyndon() {
	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 += 1;//abcdab
			}
			else ans[k] = j = i;//abcdac
			k += 1;
		}
		while(i<=j) i+=k-j;
		ans[k] = i;//abcdaa
	}
}

void solve(){
	scanf("%s",s+1);
	N = strlen(s+1);
	Lyndon();
	ll sum = 1;
	ll temp = 1112;
	FOR(i,2,N) {
		sum = sum + ans[i] * temp % mod;
		sum %= mod;
		temp *= 1112;
		temp %= mod;
	}
	printf("%lld\n",sum);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值