当前位置:网站首页>模板:P6114 【模板】Lyndon 分解&Runs(字符串)
模板:P6114 【模板】Lyndon 分解&Runs(字符串)
2022-06-21 16:01:00 【wind__whisper】
你不会连跑步都不会吧。
(逃
前言
SAM:runs?那我run了。
比 SAM 看起来层次更高的奥妙算法。
理论证明比较复杂,但板子写起来都比较简单。
本文会略过很多的证明。
Lyndon 分解
Definition:
如果一个串本身比它的所有真后缀字典序都小,我们就称这样的一个串为 Lyndon 串。
如果一个字符串的划分 w 1 w 2 . . . w k w_1w_2...w_k w1w2...wk 满足所有的 w 都是 Lyndon 串,且满足字典序 w 1 ≥ w 2 ≥ . . . ≥ w k w_1\ge w_2\ge ...\ge w_k w1≥w2≥...≥wk,则成其为字符串的 Lyndon 分解。
可以证明,任意字符串的 Lyndon 分解是唯一的。
求解
如何求呢?
设考虑到第 i 位。
此时未确定的分解必然形如 w w w . . . w ′ www...w' www...w′, w ′ w' w′ 是 w w w 的一个前缀。
如果新字符和循环节对应位置相同,不做处理。
如果新字符更大,合并成一整块。
如果新字符更小,把前面的若干个循环节分裂出来,然后回退到 w ′ w' w′,继续处理。
时间复杂度 O ( n ) O(n) O(n)。
int i=1,j=2,l=1,res(0);
for(;i<=n;j++){
if(s[j]>s[j-l]) l=j-i+1;
else if(s[j]<s[j-l]){
while(i+l<=j){
res^=(i+l-1);
i+=l;
}
j=i;l=1;
}
}
Runs
definition:
如果一个字符串的某个字串可以写成 p p p . . . p ′ ppp...p' ppp...p′ 的形式,且其是符合条件的极长子串,则称其为一个 runs。(周期p至少出现两次)
对于每一个runs,其长度恰好为p的lyndon串称为其的 lyndon根。
每个runs有且只有一个本质不同的lyndon根。
Lemma:设 l t i lt_i lti 为 max j , s ( i , j ) 为 l y n d o n 串 \max j,s(i,j)为lyndon串 maxj,s(i,j)为lyndon串,那么对于一个 lyndon 根(i,j),在 < 0 , < 1 <_0,<_1 <0,<1 两种相反的比较符定义下,至少有一种情况满足 l t i = j lt_i=j lti=j。
所以我们可以求出 l t lt lt 数组,然后通过 ( i , l t i ) (i,lt_i) (i,lti) 反推出其对应的runs(通过求lcp和lcs容易求出)。
那么如何求出 l t lt lt 呢?
lyndon 分解还有一种单调栈的求法,当栈顶字典序小于当前元素时不断把栈顶块和当前块合并。不难发现此时得到的块的右端点就是对应的 l t i lt_i lti。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned ll
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define ok debug("OK\n")
inline ll read() {
ll x(0),f(1);char c=getchar();
while(!isdigit(c)) {
if(c=='-') f=-1;c=getchar();}
while(isdigit(c)) {
x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*f;
}
const int N=1e6+100;
const int mod=1e9+7;
const int inf=1e9+100;
const double eps=1e-9;
bool mem1;
bool Flag=0;
inline ll ksm(ll x,ll k,int mod){
ll res(1);
x%=mod;
while(k){
if(k&1) res=res*x%mod;
x=x*x%mod;
k>>=1;
}
return res;
}
int n,m;
char s[N];
const int bas=31;
ull h[N],mi[N];
void init(){
mi[0]=1;
for(int i=1;i<=n;i++){
mi[i]=mi[i-1]*bas;
h[i]=h[i-1]*bas+s[i]-'a'+1;
}
return;
}
inline ll Hash(int l,int r){
return h[r]-mi[r-l+1]*h[l-1];
}
inline int lcp(int i,int j){
int st=0,ed=n-max(i,j)+1;
while(st<ed){
int mid=(st+ed+1)>>1;
if(Hash(i,i+mid-1)==Hash(j,j+mid-1)) st=mid;
else ed=mid-1;
}
return st;
}
inline int lcs(int i,int j){
int st=0,ed=min(i,j);
while(st<ed){
int mid=(st+ed+1)>>1;
if(Hash(i-mid+1,i)==Hash(j-mid+1,j)) st=mid;
else ed=mid-1;
}
return st;
}
map<int,int>mp[N];
struct run{
int l,r,p;
bool operator < (const run &oth)const{
if(l!=oth.l) return l<oth.l;
else return r<oth.r;
}
};
vector<run> ans;
inline void ins(int i,int j){
if(j==n) return;
j++;
int p=(j-i),pre=i-lcs(i,j)+1,suf=j+lcp(i,j)-1;
//printf("ins: (%d %d) (%d %d)\n",i,j,pre,suf);
if(mp[pre][suf]) return;
if(suf-pre+1>=2*p){
mp[pre][suf]=1;
ans.emplace_back((run){
pre,suf,p});
}
return;
}
int cmp(int i,int j,int x,int y){
//i<j?
int len=lcp(i,j);
//printf("i=%d j=%d x=%d y=%d len=%d\n",i,j,x,y,len);
if(len>=min(x,y)){
if(x<y) return 1;
else if(x==y) return 0;
else return -1;
}
else{
if(s[i+len]<s[j+len]) return 1;
else if(s[i+len]==s[j+len]) return 0;
else return -1;
}
}
int zhan[N],top;//zhan:right pos
void work(){
top=0;
for(int i=n;i>=1;i--){
int pos=i;
while(top&&cmp(i,pos+1,pos-i+1,zhan[top]-pos)==1) pos=zhan[top--];
//if(top) printf(" f=%d\n",cmp(i,pos+1,pos-i+1,zhan[top]-pos));
zhan[++top]=pos;
//printf("i=%d pos=%d\n",i,pos);
ins(i,pos);
}
}
bool mem2;
signed main(){
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
#endif
scanf("%s",s+1);
n=strlen(s+1);
init();
work();
for(int i=1;i<=n;i++) s[i]='a'-s[i]+1;
work();
sort(ans.begin(),ans.end());
printf("%d\n",(int)ans.size());
for(run o:ans) printf("%d %d %d\n",o.l,o.r,o.p);
return 0;
}
/* */
边栏推荐
- Generating test reports using the unittest framework
- Unittest框架
- Google Earth engine (GEE) - sentinel-1 comprehensively check the difference between automatic landslide monitoring before and after two months (Guatemala as an example)
- The Google play academy team PK competition officially begins!
- 微信小程序开发入门介绍-布局组件
- 叩富网可以开期货账户吗?安全吗?
- 微信小程序-image加载图片工具中显示,真机中不显示
- Simulation Implementation of string class
- VNC Viewer方式的远程连接树莓派
- [1108. IP address invalidation]
猜你喜欢

ESP8266/ESP32 通過TimeLib庫獲取NTP時間方法

I do 3D restoration for the aircraft carrier: these three details are shocking

好用不贵!11款开源自动化安全测试工具简介

Pytest--生成测试报告

海外new things | 软件开发商「Dynaboard」种子轮融资660万美元,开发低代码平台连接设计、产品和开发人员

The Google play academy team PK competition officially begins!

In 2021 database market, aerospike competes with top manufacturers

Online JSON to yaml tool

我给航母做3D还原:这三处细节,太震撼了…

Serious illness insurance covers serious illness. Which product is the best in the market? Please recommend it
随机推荐
Go语言开发代码自测绝佳go fuzzing用法详解
HUAWEI(13)——路由引入
[observation] Microsoft's "cloud + end" comprehensive innovation makes hybrid cloud simpler, more flexible and more secure
【SQLite】解决unrecognized token:“‘“
Cloud native hybrid cloud network interconnection
如何判断DNS解析故障?如何解决DNS解析错误?
重磅丨国内首份呈现数据库发展历程的图鉴正式发布!
Alibaba cloud server + pagoda panel + no domain name deployment web project
Focusing on industrial intelligence scenarios, Huawei cloud recruits partners to help solve transformation problems
4. 构造【LR(1)分析表(包含构建项目规范族)】
[从零开始学习FPGA编程-38]:进阶篇 -语法-函数与任务
【1108. IP 地址無效化】
Growth is not necessarily related to age
Overseas new things | zoovu, an American AI startup, raised a new round of financing of US $169million to optimize the online "product discovery" experience for consumers
Notice on Revising the guidelines for the planning, design and livable construction of housing with common property rights in Beijing (for Trial Implementation)
强化学习入门项目spinning up(1)安装
[1108. IP address invalidation]
成长和年龄没有必然联系
Can Koufu open a futures account? Is it safe?
[mathematical modeling] Matlab Application Practice Series (95) - application cases of time series prediction (with matlab code)