「学习笔记」Lyndon 理论(一)

字符串,太深刻了。

Lyndon 理论,太神奇了。


本文详细介绍了 Lyndon 理论的相关内容,并且几乎所有定理和推论都给出了相关证明,同时部分算法给了几道配套例题。

希望读者阅读后能对 Lyndon 理论有深刻的理解。

全篇太长了,故分开来发。

0. 初步的定义 & 约定

  • 长度:记为 $|s|$。

  • 字符:用 $s[i]$ 表示串 $s$ 的第 $i$ 个字符。$s$ 中的字符标号为 $1,2,\ldots,n$。单个字符也被视作字符串。

  • 字符集:记为 $\Sigma_s$。

  • 字符串的比较:若 $s$ 的字典序比 $t$ 小,记为 $s<t$。类似地有 $\leq,>,\geq$。

  • 子串:$s[l\dots r]$ 表示将 $s[l],s[l+1],\ldots,s[r]$ 顺次连接而成的字符串。

  • 前缀 & 后缀:前缀为字符串开头的子串,即 $s[1\dots i]$;后缀为字符串结尾的子串,即 $s[i\dots n]$

    记 $\mathrm{pre}(s)$ 为 $s$ 的前缀集合,$\mathrm{suf}(s)$ 为 $s$ 的后缀集合。

  • 真前缀 & 真后缀:称一个前缀/后缀为真前缀/真后缀,当且仅当它与原串 $s$ 不相等。

  • 字符串的拼接:记 $st$,$s \cdot t$ 为字符串 $s$,$t$ 顺次连接而得的串。

  • 字符串的幂:定义 $s^k = \overbrace{ss\ldots s}^{\text{共 } k \text{ 个}}$,即 $k$ 个 $s$ 顺次连接而得的串。

1. Lyndon 串(Lyndon Word)

1.1 定义

  • Lyndon 串(Lyndon Word):对于字符串 $s$,如果 $s$ 的字典序严格小于 $s$ 的所有后缀的字典序,我们称 $s$ 是 Lyndon 串。换句话说,对于一个字符串,若其本身就是其最小后缀,则称它为 Lyndon 串。
  • Lyndon 前缀(Lyndon Prefix):如果字符串 $s$ 的一个前缀 $s[1 \dots i]$ 是一个 Lyndon 串,那么它就是一个 Lyndon 前缀。
  • Lyndon 后缀(Lyndon Suffix):如果字符串 $s$ 的一个后缀 $s[i \dots n]$ 是一个 Lyndon 串,那么它就是一个 Lyndon 后缀。

1.2 性质

  • 引理 1.2.1:若字符串 $a$ 和 $b$ 互不为对方的前缀,则对于任意 $c_1, c_2$,$ac_1 < bc_2 \Leftrightarrow a < b$。

充分性:因为 $a$ 不是 $b$ 的真前缀,那么比较完前 $min{|a|,|b|}$ 位就可以确定 $a<b$。

必要性:显然。

  • 引理 1.2.2:若字符串 $a$ 和 $b$ 长度相同,则对于任意 $c_1, c_2$,$ac_1 < bc_2 \implies a \le b$。

如果 $a>b$,显然 $ac_1 > bc_2$,矛盾。

故 $a \le b$。

  • 定理 1.2.1:Lyndon 串的字典序严格小于其所有的非空真后缀。

根据定义可得。

  • 定理 1.2.2:对于任意一个长度大于 1 的 Lyndon 串 $s$,其不存在 Border(即不存在既是真前缀又是真后缀的子串)。

如果 $s$ 有一个 Border $t$,那么 $t$ 是 $s$ 的真后缀,根据定义 $s < t$。但 $t$ 也是 $s$ 的前缀,前缀的字典序不可能大于原串,产生矛盾。

  • 定理 1.2.3:对于任意一个 Lyndon 串 $s=ab$,有 $a<b$($a,b$ 均非空)。

由定义有 $ab<b$,且显然有 $a<ab$,所以 $a<b$。

  • 推论 1.2.3.1:对于任意一个 Lyndon 串 $s$,其真前缀和真后缀分别为 $a$ 和 $b$,有 $a<b$($a,b$ 均非空)。

由定义有 $s<b$,且显然有 $a<s$,所以 $a<b$。

  • 推论 1.2.3.2:对于任意一个 Lyndon 串 $s$ 的前缀 $t$(可以有 $t$ 和 $s$ 相等),其真后缀的字典序始终大于或等于与其长度相同的真前缀。形式化地讲,$\forall i\in[2, |t|]$,都满足:
    $$t[i \dots |t|] \ge t[1 \dots |t|-i+1]$$

令 $s=tv$。

根据定义,有:$$t[i \dots |t|]v > tv$$

我们考虑前 $|t|-i+1$ 个字符,分别是 $t[i \dots |t|]$ 和 $t[1 \dots |t|-i+1]$。

根据引理 1.2.2,有:$$t[i \dots |t|]\ge t[1 \dots |t|-i+1]$$

证毕。

  • 定理 1.2.4:对于任意一个串 $a$ 和任意一个 Lyndon 串 $b$ ,有 $a<b \Leftrightarrow ab<b$

情况一:若 $a$ 不是 $b$ 的真前缀

充分性:显然成立。

必要性:若 $|a|\geq |b|$,显然有 $a<b$;若 $|a|<|b|$,$b$ 不可能是 $a$ 的真前缀,根据引理 1.2.1,可得 $a<b$。

情况二:若 $a$ 是 $b$ 的真前缀

充分性:令 $b=at$,即证 $b<t$,其中 $t$ 为 $b$ 的后缀。根据 Lyndon 串的定义,显然有 $b<t$。

必要性:显然有 $a<b$ ,必要性成立。

  • 定理 1.2.5:$s$ 是 Lyndon 串当且仅当 $s=ab$,$a<b$ 且 $a,b$ 均为 Lyndon 串($a,b$ 均非空,$|s|\geq2$)。

充分性:$a < b$ 且 $a, b$ 均为 Lyndon 串 $\Rightarrow$ $ab$ 是 Lyndon 串。

我们要证明 $ab$ 是 Lyndon 串,即证明其严格小于它的所有非空真后缀。

$ab$ 的真后缀可以分为 $suf(a)b, b, suf(b)$ 。

由定义有 $a < suf(a)$,显然有:

$$ab < suf(a)b$$

由定理 1.2.4 有 $ab < b$,又 $b < suf(b)$,故:

$$ab < b < suf(b)$$

综上,$ab$ 严格小于其所有真后缀,故 $ab$ 是 Lyndon 串,证毕。

必要性:$s$ 是 Lyndon 串 $\Rightarrow$ 存在 $i$ 使得 $s[1\dots i-1]<s[i\dots n]$ 且 $s[1\dots i-1],s[i\dots n]$ 均为 Lyndon 串。

令 $b$ 为 $s$ 的最小真后缀,$s=ab$。(这里的 $a,b$ 即是命题中的 $s[1\dots i-1],s[i\dots n]$)

由定理 1.2.3,有 $a<b$。

因为不存在比 $b$ 更小的真后缀,故 $b$ 为 Lyndon 串。

考虑后缀 $suf(a)b$,有 $suf(a)b>b$,又根据定义有 $b>s=ab$,则 $$suf(a)b>ab$$

若 $suf(a)$ 不是 $a$ 的真前缀,因为 $a$ 不可能是 $suf(a)$ 的真前缀,由引理 1.2.1,可得 $suf(a)>a$,故 $a$ 为 Lyndon 串。

若 $suf(a)$ 是 $a$ 的真前缀,即 $pre(a)=suf(a)$,带入上式得 $pre(a)b>ab$,把相同的前缀拿掉后,有 $b>suf'(a)b$(注意这里 $suf'(b)$ 不一定和 $suf(a)$ 相等),与 $b$ 是 $s$ 的最小真后缀矛盾,故 $suf(a)$ 不能是 $a$ 的真前缀。

综上,$a$ 为 Lyndon 串,证毕。

  • 定理 1.2.6:若字符串 $v$ 和字符 $c$ 满足 $vc$ 是某个 Lyndon 串 $s$ 的前缀,则对于字符 $d > c$ 有 $vd$ 是 Lyndon 串。

设 $s=vct$,由定义得 $v[i\dots |v|]ct>vct$。

我们要证明 $vd$ 是 Lyndon 串,即证明其严格小于它的所有非空真后缀。真后缀分为两种情况:

情况一:长度大于 1 的真后缀,形如 $v[i\dots |v|] d \quad (i \in [2, |v|])$。

比较两边前 $|v|-i+2$ 个字符(即只比到 $c$ 的位置),由引理 1.2.2,必然有:

$$v[i\dots |v|] c \ge v[1 \dots |v|-i+2]$$

又 $d > c$,有:

$$v[i\dots |v|] d > v[1 \dots |v|-i+2]$$

因此,在字典序比较中,$v[i\dots |v|] d$ 在前缀阶段就已经严格大于 $vd$ 的前缀,则有:

$$v[i\dots |v|] d>vd$$

情况二:长度为 1 的真后缀,即 $d$。

因为 $s$ 是 Lyndon 串,显然其首字符 $v[1]$ 必然是 $s$ 中字典序最小的字符(或之一),故必有:

$$c \ge v[1]$$

结合已知条件 $d > c$,可得:

$$d > v[1]$$

故:

$$d>vd$$

综上,$vd$ 严格小于其所有真后缀,故 $vd$ 是 Lyndon 串。证毕。

2. Lyndon 分解(CFL 分解)

2.1 定义

  • Lyndon 分解:字符串 $s$ 的 Lyndon 分解记为 $s=w_1w_2\dots w_k$,其中所有 $w_i$ 为 Lyndon 串,并且他们的字典序按照非严格递减排序,即 $w_1\geq w_2\geq\dots\geq w_k$。可以发现,这样的分解存在且唯一。

2.2 性质

在 Lyndon 分解 $s = w_1 w_2 \dots w_k$ 中

  • 定理 2.3.1:任何字符串的 Lyndon 分解都是唯一的。

假设存在两种分解方式,证明矛盾即可。

这里就偷懒不证了。

  • 定理 2.3.2:如果截取分解中的连续一段 $wi w{i+1} \dots w_j$(其中 $1 \le i \le j \le k$),这段子串的 Lyndon 分解恰好就是 $wi, w{i+1}, \dots, w_j$ 本身。

显然 $wi, w{i+1}, \dots, w_j$ 符合 Lyndon 分解的定义,并且由于 Lyndon 分解的唯一性,故 $wi w{i+1} \dots w_j$ 的 Lyndon 分解恰好就是 $wi, w{i+1}, \dots, w_j$ 本身

  • 定理 2.3.3:Lyndon 分解中的最后一个 Lyndon 因子 $w_k$ 必然是整个字符串 $s$ 的字典序严格最小的后缀。

我们要证明对于 $s$ 的任意非空后缀 $t$,都有 $w_k \le t$。

$s$ 的后缀可以分为两类:

情况一: $t$ 是 $w_k$ 的一个非空后缀。

根据定义,$w_k \le t$ 显然成立。

情况二:$t$ 跨越了多个因子

设后缀 $t = wi' w{i+1} \dots w_k$,其中 $w_i'$ 是 $w_i$ 的某个后缀(可以是 $w_i$ 本身),且 $i < k$。

假设此时恰有 $w_i'=w_i$。

如果 $w_i > w_k$,故 $t=wi w{i+1} \dots w_k > w_k$。

如果 $w_i = w_k$,由于 $w_1\geq w_2\geq\dots\geq w_k$,显然中间所有的因子也必须相等,即 $wm = w{m+1} = \dots = w_k$。此时 $t = w_k^r$(其中 $r$ 是因子的个数),显然 $t=w_k^r > w_k$。

即使 $w_i'$ 是 $w_i$ 的真后缀,根据 Lyndon 串定义 $w_i' > w_i$,同样可以推导出 $t=wi' w{i+1} \dots w_k > w_k$。

  • 定理 2.3.4:Lyndon 分解中的第一个 Lyndon 因子 $w_1$ 是 $s$ 的最长 Lyndon 前缀;最后一个因子 $w_k$ 是 $s$ 的最长 Lyndon 后缀。

我们要证明:对于任何长度大于 $|w_1|$ 的前缀 $p = s[1 \dots j]$(即 $j > |w_1|$),$p$ 一定不是 Lyndon 串。

设 $p$ 跨越了前 $r$ 个 Lyndon 因子($r \ge 2$),即 $p = w_1 w2 \dots w{r-1} w_r'$,其中 $w_r'$ 是 $w_r$ 的一个非空前缀(可以是 $w_r$ 本身)。

根据 Lyndon 分解的性质,$w_1 \ge w_2$,我们可以分类讨论。

情况一:$w_1 > w_2$

往后面加一些东西显然不改变不等号方向,于是有 $w_1 w_2 \dots > w_2 \dots$。

由于 $p$ 拥有一个真后缀 $suf(p) = w_2 \dots w_r'$,显然 $p > suf(p)$。

根据 Lyndon 串的定义,$p$ 不是 Lyndon 串。

情况二:$w_1 = w_2$

有 $p = w_1 w2 \dots w{r-1} w_r' = w_1 w1 \dots w{r-1} w_r'$。

那么 $p$ 的一个真后缀就是 $suf(p)=w_2 \dots w_r'=w_1 \dots w_r'$。

不难发现前缀都有 $w_1$,此时只需比较 $w_1w3 \dots w{r-1} w_r'$ 和 $w_3 \dots w_r'$。

若 $w_1 > w_3$,显然有 $p > suf(p)$,$p$ 不是 Lyndon 串。

若 $w_1 = w_3$,重复上述步骤,后面以此类推。

如果一直相等,最后会剩下 $w_1 w_r'$ 和 $w_r'$,由于 $w_1\ge w_r \ge w_r'$,那么 $w_1 w_r'>w_r'$,于是有 $p > suf(p)$,$p$ 不是 Lyndon 串。

综上,始终有 $p > suf(p)$,故 $p$ 不是 Lyndon 串,证毕。

后缀的证明和前缀类似,节省空间,这里就不证了。

  • 定理 2.3.5:后缀 $s[i \dots n]$ 的第一个 Lyndon 因子的末尾,恰好在“第一个字典序严格小于 $s[i \dots n]$ 的后缀”出现的位置之前。

令 $t=s[i \dots n]$。

设 $t$ 的唯一 Lyndon 分解为 $t = w_1 w_2 \dots w_k$,且 $w_1 \ge w_2 \ge \dots \ge w_k$。

我们首先证明:对于所有起始于 $w_1$ 内部的位置 $j$(即 $1 < j \le |w_1|$),以它开头的后缀 $t[j\dots n]$ 一定严格大于 $t$,即 $t[j\dots n]>t$。

显然 $t[j\dots n] = w_1[j \dots |w_1|] w_2 \dots w_k$。

我们要将它与原串 $t = w_1 w_2 \dots w_k$ 进行比较。

根据 Lyndon 串的定义,$w_1$ 严格小于它的所有真后缀。因此:

$$w_1 < w_1[j \dots |w_1|]$$

根据定理 1.2.2,$w_1[j \dots |w_1|]$ 不是 $w_1$ 的前缀,又因为 $w_1$ 显然不可能是 $w_1[j \dots |w_1|]$ 的前缀,根据引理 1.2.1,有:

$$w_1 w_2 \dots w_k < w_1[j \dots |w_1|] w_2 \dots w_k$$

即 $t<t[j\dots n]$。

接下来我们需要证明:以 $|w_1| + 1$ 开头的后缀,一定严格小于 $t$,即 $t[|w_1| + 1\dots n]<t$。

显然 $t[|w_1| + 1\dots n] = w_2 w_3 \dots w_k$。

我们只需证明 $w_2 w_3 \dots w_k<w_1 w_2 \dots w_k$。

考虑到 $w_1 \ge w_2 \ge \dots \ge w_k$,假设前 $r$ 个 Lyndon 因子完全相等,即 $w_1 = w_2 = \dots = wr > w{r+1}$(若 $r = k$,则 $w_{r+1}$ 视为空串)。

此时我们只需证 $w1^{r-1} w{r+1} \dots w_k<w1^r w{r+1} \dots w_k$。

它们拥有公共前缀 $w_1^{r-1}$。将其消去后,问题转化为比较以下两个字符串:

$$A = w{r+1} w{r+2} \dots w_k,B = w1 w{r+1} \dots w_k$$

如果 $A$ 是空串,那么 $A < B$ 显然成立。

如果 $A$ 不是空串,我们已知 $w1 > w{r+1}$,此时需要分两种情况:

情况一:$w_{r+1}$ 不是 $w_1$ 的真前缀

这种情况下由于 $w1 > w{r+1}$ 且不包含前缀关系,由引理 1.2.1,显然有 $A < B$。

情况二:$w_{r+1}$ 是 $w_1$ 的真前缀

设 $w1 = w{r+1} u$($u$ 不能为空)。

此时

$$A = w{r+1} w{r+2} \dots wk,B = w{r+1} u w_{r+1} \dots w_k$$

因为 $w_1$ 是 Lyndon 串,根据定义有 $u > w_1$。

于是有 $u > w1 \ge w{r+1} \ge w{r+2}$,即 $u > w{r+2}$。

现在,我们在 $A$ 和 $B$ 中同时消去公共前缀 $w_{r+1}$,剩下:

$$A' = w_{r+2} \dots wk,B' = u w{r+1} \dots w_k$$

此时 $A'$ 以 $w{r+2}$ 开头,$B'$ 以 $u$ 开头,且已知 $u > w{r+2}$。你会发现,这与我们刚才面临的局面完全一致。

我们可以不断重复上述过程。由于每次 $B$ 剩余部分开头的字符串,必然是上一轮 $u$ 的真后缀,因此它也就是 $w_1$ 的某个真后缀。根据 Lyndon 性质,它永远严格大于 $w_1$,自然也严格大于下一个将要比较的 Lyndon 因子 $w_j$。

最终要么遇到了情况一结束,要么重复情况二直到 $A$ 的因子被消耗殆尽变成空串,而此时 $B$ 还有剩余,于是一定有 $A < B$。

证毕。

  • 推论 2.3.5.1:对于任意字符串的 Lyndon 分解,总有 $w_1\dots w_k>w_2 \dots wk>\dots>w{k-1} w_k> w_k$。

2.3 算法

2.3.1 Duval 算法

Duval 可以在 $\mathcal{O}(n)$ 的时间内求出一个串的 Lyndon 分解。

该算法需要维护三个变量 $i,j,k$,这三个指针将整个字符串分成了四个部分 $s[1,i-1],s[i,k-1],s[j,k-1],s[k,n]$ :

  • $s[1,i-1]$:这部分的 Lyndon 分解已经完成。
  • $s[i,k-1]$:这部分可以被表示成 $t^h+v$,其中 $t$ 是一个 Lyndon 串,$t^h$ 表示 $t$ 循环 $h$ 次,$v$是 $t$ 的一个可空真前缀。
  • $s[j,k-1]$:注意这部分是包含在上一个部分中的,其中$j=k–|t|$。
  • $s[k,n]$:这部分还未处理,此时正在考虑 $k$。

考虑k有三种情况:

  • $s_j=s_k$:可以将 $t$ 继续循环下去,因此 $j$ 往后移一位,考虑下一个 $k$。
  • $s_j<s_k$:可以将 $t^c+v+s_k$ 合并为一个 Lyndon 串,因此 $j$ 设为 $i$,考虑下一个 $k$。
  • $s_j>s_k$:可以将 $t$ 单独作为 Lyndon 分解中的一个串,然后从 $v$ 的开头开始重新考虑,因此 $i$ 设为 $v$ 的开头,$j,k$ 分别设为 $i,i+1$。
string s;
cin&gt;&gt;s;
int n=s.length();
s=&#039; &#039;+s;
for(int i=1;i&lt;=n;){
    int j=i,k=i+1;
    while(k&lt;=n and s[j]&lt;=s[k]){
        if(s[j]&lt;s[k])j=i;
        else j++;
        k++;
    }
    while(i&lt;=j){
        cout&lt;&lt;i+k-j-1&lt;&lt;&#039; &#039;;  //分解后每个 Lyndon 串的右端点
        i+=k-j;
    }
}

2.3.2 SA + 单调栈算法

注意:这个算法远不及 Duval 算法高效,平时最常用还是 Duval 算法,写在这里仅为了拓宽思路。(事实上,某些题甚至可以用 Lyndon 分解吊打 SA,同时也存在用 Lyndon 理论求 SA 的算法)

我们求出后缀数组(SA)和 $rank$ 数组后。

根据定理 2.3.5,这个问题转化为:在 $rank$ 数组中,寻找 $i$ 后面第一个 $j$ 使得 $rank[j] < rank[i]$。

我们用单调栈对 $rank$ 数组预处理一下,就能 $O(1)$ 找到 $j$ 了。

复杂度:$O(n)$ 或 $O(n \log n)$ 取决于 SA 的实现。

2.4 应用

  • 求每个前缀的最小前缀/后缀。

  • 求字符串的最小表示法。

  • 等等。

2.5 例题

HDU6761 Minimum Index

题意:求每个前缀的最小后缀的起始位置下标。

题解:

根据定理 2.3.1,对于每个前缀我们取最后一个 Lyndon 因子就是答案。Duval 过程中边找边记录答案即可。

#include &lt;bits/stdc++.h&gt;
using namespace std;
typedef unsigned long long ll;
#define int ll
const int maxn = 20000005, mod = 1000000007, INF = 1e9;
int ans[maxn];

void solve() {
    string s;
    cin&gt;&gt;s;
    int n=s.length();
    s=&#039; &#039;+s;
    ans[1]=1;
    for(int i=1;i&lt;=n;){
        int j=i,k=i+1;
        while(k&lt;=n and s[j]&lt;=s[k]){
            if(s[j]&lt;s[k])ans[k]=j=i;
            else ans[k]=ans[j]+k-j,j++;
            k++;
        }
        while(i&lt;=j){
            i+=k-j;
        }
        ans[k]=i;
    }
    int sum=0;
    for(int i=1,x=1;i&lt;=n;i++,x=x*1112LL%mod){
        sum+=ans[i]*x%mod;
        sum%=mod;
    }
    cout&lt;&lt;sum&lt;&lt;&#039;\n&#039;;
}

signed main() {
    ios::sync_with_stdio(0);
    int t = 1;
    cin &gt;&gt; t;
    while (t--) {
        solve();
    }

    return 0;
}

P13270 【模板】最小表示法

题意:给定一个长度为 $n$ 的字符串 $s$,求与 $s$ 循环同构的字典序最小的串(即字符串 $s$ 的最小表示)。

题解:

设 $t = ss$,则需要找出 $t$ 的长度为 $n$ 的最小子串。

对 $t$ 做 Lyndon 分解,然后寻找这个分解中的一个 Lyndon 串 $w_i$,使得它的起点小于 $n$ 且终点大于等于 $n$。

可以很容易地使用 Lyndon 分解的性质证明,子串 $w_i$ 的首字符就是 $s$ 的最小表示法的首字符,即我们沿着 $w_i$ 的开头往后 $n$ 个字符组成的串就是 $s$ 的最小表示法。

#include &lt;bits/stdc++.h&gt;
using namespace std;
typedef long long ll;
const int maxn = 5000050, mod = 1e9 + 7, INF = 1e9;

int main() {
    ios::sync_with_stdio(0);
    int n;
    cin&gt;&gt;n; 
    string s;
    cin&gt;&gt;s;
    s=&#039; &#039;+s+s;
    int ans=0;
    for(int i=1;i&lt;=2*n;){
        int j=i,k=i+1;
        while(k&lt;=2*n and s[j]&lt;=s[k]){
            if(s[j]&lt;s[k])j=i;
            else j++;
            k++;
        }
        while(i&lt;=j){
            if(i+k-j-1&lt;n) ans=max(ans,i+k-j-1)+1;
            i+=k-j;
        }
    }
    cout&lt;&lt;s.substr(ans,n)&lt;&lt;&#039;\n&#039;;

    return 0;
}

P14190 [ICPC 2024 Hangzhou R] Dividing Sequence

题意:给定一个长度为 $n$ 的字符串 $s$,将其拆成两个子序列 $a$ 和 $b$,使得字典序 $a<b$ 且最小化 $b$ 的字典序。

题解:

考虑对原串 $s$ 做 Lyndon 分解 $s = w_1 w_2 \dots w_k$,且 $w_1\geq w_2\geq\dots\geq w_k$。

$i$ 从 1 开始,

若 $w{2i-1}=w{2i}$,则将这两个串分别接在 $a,b$ 的末尾,$i++$。

若 $w{2i-1}\neq w{2i}$,将 $w_{2i-1}$ 接到 $b$ 之后,剩下的所有串按顺序接到 $a$ 的末尾,此时的$b$就是答案。

详细证明可以见题解区,这里就不证了。

#include &lt;bits/stdc++.h&gt;
using namespace std;
typedef long long ll;
const int maxn = 5000050, mod = 1e9 + 7, INF = 1e9;

void solve() {
    int n;
    cin&gt;&gt;n;
    vector&lt;int&gt; s(n+1);
    for(int i=1;i&lt;=n;i++){
        cin&gt;&gt;s[i];
    }
    vector&lt;int&gt; ans;
    for(int i=1;i&lt;=n;){
        int j=i,k=i+1;
        while(k&lt;=n and s[j]&lt;=s[k]){
            if(s[j]&lt;s[k])j=i;
            else j++;
            k++;
        }
        int f=0;
        int len=k-j;
        while(i&lt;=j){
            f^=1;
            if(f){
                for(int t=i;t&lt;=i+len-1;t++){
                    ans.push_back(s[t]);
                }
            }
            i+=len;
        }
        if(f) break;
    }
    cout&lt;&lt;ans.size()&lt;&lt;&#039;\n&#039;;

    for(int x:ans){
        cout&lt;&lt;x&lt;&lt;&#039; &#039;;
    }
    cout&lt;&lt;&#039;\n&#039;;
}

int main() {
    ios::sync_with_stdio(0);
    int t = 1;
    cin &gt;&gt; t;
    while (t--) {
        solve();
    }

    return 0;
}

参考资料 :

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
Copyright 2020-2025 西瓜nd
Theme Argon By solstice23