1 条题解
-
0
自动搬运
来自洛谷,原作者为

wucstdio
这个家伙不懒,但还是什么都没留下搬运于
2025-08-24 22:17:33,当前版本为作者最后更新于2020-02-18 16:33:06,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
大概是我贡献的第二道模板?
分解详解
我们定义一个串是 串,当且仅当这个串的最小后缀就是这个串本身。
该命题等价于这个串是它的所有循环表示中字典序最小的。
引理 1:如果 和 都是 串并且 ,则 也是 串。
证明:
1、若
这时, 和 这两个串在 之前就出现了不同的字符,所以有 ,又因为 是 串,所以 的所有后缀都大于 ,所以 的所有后缀都大于 ,故 是 串。
2、若
若 不是 的前缀,那么有 ,得证。
若 是 的前缀,那么如果 ,则必有 (也就是各自去掉了前 个字符),矛盾。
我们定义一个串 的 分解为一个字符串序列 ,满足:
- ,满足 是 串。
- ,满足 。
可以证明这种划分存在且唯一。
存在性证明
初始令 并且 ,然后每次不断找到 并且合并为一个串。最后一定能使得所有的 。
唯一性证明
假设对于字符串 存在两个 分解:
$$S=A_1A_2\cdots A_iA^\prime_{i+1}A^\prime_{i+2}\cdots A^\prime_{m_1} $$不妨设 $\operatorname{len}(A_{i+1})>\operatorname{len}(A^\prime_{i+1})$。
观察 在第二种分解中的对应情况。假设 $A_{i+1}=A^\prime_{i+1}A^\prime_{i+2}\cdots A^\prime_{k}A^\prime_{k+1}[:l]$。
那么由 串的性质可知:
$$A_{i+1}<A^\prime_{k+1}[:l]\le A^\prime_{k+1}\le A^\prime_{i+1}<A_{i+1} $$矛盾。
引理2:若字符串 和字符 满足 是某个 串的前缀,则对于字符 有 是 串。
证明:
设该 串为 。
则 ,也就是说 。
所以 。
同时因为 ,我们有 。
故 是一个 串。
算法
这个算法可以在 时间复杂度, 空间复杂度内求出一个串的 分解。
该算法中我们仅需维护三个变量 。
维持一个循环不变式:
- 是固定下来的分解,也就是 是 串且 。
- 是没有固定的分解,满足 是 串,且 是 的可为空的不等于 的前缀,且有
如下图:

当前读入的字符是 ,令 。
分三种情况讨论:
- 当 时,直接 ,周期 继续保持
- 当 时,由引理 2 可知 是 串,由于 分解需要满足 ,所以不断向前合并,最终整个 形成了一个新的 串。
- 当 时, 的分解被固定下来,算法从 的开头处重新开始。
复杂度分析: 只会单调往右移动,同时 每次移动的距离不会超过 移动的距离,所以时间复杂度是 的。
代码如下:
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; char s[5000005]; int n,ans; int main() { scanf("%s",s+1); n=(int)strlen(s+1); for(int i=1;i<=n;) { int j=i,k=i+1;//初始化 while(k<=n&&s[j]<=s[k]) { if(s[j]<s[k])j=i;//合并为一整个 else j++;//保持循环不变式 k++; } while(i<=j)//从v的开头重新开始 { ans^=i+k-j-1; i+=k-j; } } printf("%d\n",ans); return 0; }
- 1
信息
- ID
- 5139
- 时间
- 300ms
- 内存
- 500MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者