JSCPC2021Reverse the String(Lyndon 理论)

Posted Alfalfa_w

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JSCPC2021Reverse the String(Lyndon 理论)相关的知识,希望对你有一定的参考价值。

传送门

题意

给定字符串 \\(s\\),问任意翻转一个区间 \\([l,r]\\) 后得到的最小字符串。

\\(\\sum |s| \\le 1.5\\times 10^6\\)

分析

依次考虑答案第 \\(i\\) 位能否比 \\(s_i\\)​​ 小可得:\\(l\\) 一定是右边有字符比它小的最左位置。因此只需考虑翻一个前缀的情况,可以用二分+哈希比较出最小答案,但是有线性做法。

\\(t=s^R\\),我们要把 \\(t\\) 划分成 \\(t_1t_2\\),使得 \\(t_2t_1^R\\) 最小。

直接在 \\(t\\)​ 上跑 Duval 算法。记当前位为 \\(i\\)​,和它比较的位为 \\(j\\)​。当出现 \\(t_i<t_j\\)​ 时,之前所有整周期内的位置都不可能为 \\(t_2\\)​​ 的开头,因为严格比不上选 \\(i\\)​ 所在的半周期的开头,因此可以把整周期丢掉不管。

最终 \\(t\\) 的剩余部分能划分为 \\(w^pw\'\\) 的形式,其中 \\(w\\) 为 lyndon 串且 \\(w\'\\)\\(w\\) 的可空前缀,而 \\(t_2\\) 的开头一定是某个 \\(w\\)\\(w\'\\) 的开头。

考虑三个串 \\(x,y,z\\)​​​​ 且 \\(|x|=|y|\\)​​​​。那么 \\(xzy\\)​​​​ 不可能比 \\(xxz,zyy\\)​ 都小,否则 \\(xz>zy\\)​​ 和 \\(xz<zy\\)​ 同时成立导出矛盾。代入 \\(x=w^R,y=w,z=w\'\\)​ 得出答案只能是 \\(w\'w^Rp\\)​ 和 \\(w^pw\'\\)​ 之一,比较两种方案的字典序即可。

实现

提交记录

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a),_=(b);i<=_;++i)
#define per(i,a,b) for(int i=(a),_=(b);i>=_;--i)
using namespace std;
typedef long long ll;
typedef unsigned long long ul;
typedef reverse_iterator<int*>RI;
#define pb push_back
#define IL inline
const int mod=998244353;
IL int inc(int x,int y)return x+=y-mod,x+=x>>31&mod;
IL int dec(int x,int y)return x-=y,x+=x>>31&mod;
IL int mul(int x,int y)return ul(x)*y%mod;
IL int idk(int x,int y,int p)return p&1?dec(x,y):inc(x,y);
IL int ksm(int x,int y,int p=1)
	for(;y;y>>=1,x=mul(x,x))if(y&1)p=mul(x,p);
	return p;

//head
const int N=1e5+5;
int T,n,m,mn[N],l;
char s[N],t[N],res[N],tmp[N];
void upd(int r)
	rep(i,1,n+1)tmp[i]=s[i];
	reverse(tmp+l,tmp+r+1);
	if(strcmp(tmp+1,res+1)<0)rep(i,1,n)res[i]=tmp[i];

int main()
	scanf("%d",&T);
	while(T--)
		scanf("%s",s+1),n=strlen(s+1);
		mn[n]=s[n]-\'a\';
		per(i,n-1,1)mn[i]=min(mn[i+1],s[i]-\'a\');
		l=m=0;
		rep(i,1,n)if(mn[i]<s[i]-\'a\')l=i;break;
		if(!l)puts(s+1);continue;
		per(i,n,l)t[++m]=s[i];
		rep(i,1,n+1)res[i]=s[i];
		for(int i=2,j=1,k=1;i<=m+1;)
			if(i==m+1)
				upd(n+1-k);
				while(k<j)k+=i-j;
				upd(n+1-k);
				puts(res+1);
				break;
			
			if(t[i]==t[j])
				++i,++j;
			else if(t[i]>t[j])
				++i,j=k;
			else
				while(k<=j)k+=i-j;
				i=j=k,++i;
			
		
	
	exit(0);


以上是关于JSCPC2021Reverse the String(Lyndon 理论)的主要内容,如果未能解决你的问题,请参考以下文章

tf.reverse()

攻防世界-reverse-reverse-for-the-holy-grail-350

攻防世界 reverse Guess-the-Number

1121 - Reverse the lights 思维题

玲珑杯 Round15 A Reverse the light

攻防世界 reverse 进阶 8-The_Maya_Society Hack.lu-2017