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

qwaszx
不再为往事受困.搬运于
2025-08-24 22:09:40,当前版本为作者最后更新于2021-03-11 19:44:37,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
使用 Lyndon word 相关理论可以导出本题的一个简洁线性做法
zx 哥哥的线性做法,然而我并没有看懂.
首先考虑如果给定一个串 ,那么什么样的位置可能是最小表示
对 做 Lyndon 分解,合并相同的 Lyndon word,会得到 ,其中
首先显然选择的位置一定是 Lyndon word 的开头,接下来我们断言如果选择了 ,那么 .
证明:只需比较 的大小. 如果 ,那么自然有 ;否则,如果 不是 的前缀,那么有 ;如果 是 的前缀,那么我们可以把 不断去掉前缀 来变成之前的情况,从而 总是不优的. 注意这个证明并没有使用 Lyndon word 的任何性质,这对一般的字符串也是成立的.
注意到一个性质:如果 是任意串, 是 Lyndon word,,那么
设 . 由于 且 是 Lyndon word,容易推出 . 首先 可能是一个最小表示的开始,接下来如果 不是 的前缀那么所有 的 都无法成为最小表示. 如果是前缀,那么再考虑如果 不是 的前缀,则所有 的 都无法成为最小表示. 以此类推,我们能找到一个最小的 ,满足 有 是 的前缀. 只有这些 的 可能成为最小表示.
注意到这已经导出了一个 做法: 每减小 后缀长度至少乘二,因此可行的 只有 个. 我们维护每个前缀的 Lyndon 分解(用单调栈维护当前所有 Lyndon word(形如 ),每次插入一个 ,如果栈顶元素小于加入的 Lyndon word 就将其合并,否则就得到了最后一个 Lyndon word),暴力向前枚举上面所说的后缀即可.
但我们不满足于此. 还是来考虑 Duval 算法,设当前考虑到的字符串为 ,其中 是 的可空真前缀, 是 Lyndon word. 在运行过程中同时维护每个原串前缀的最小表示的起始位置,设为 . 考虑加入一个字符 造成的影响. 我们首先给出结论,然后给出证明. 设 的位置为 且之前未被更新过,那么
- 如果 ,那么 为 和 中更优的那个
- 如果 ,那么
- 如果 ,那么等到以后再更新.
考虑其正确性,我们在什么时候会进行新的一轮遍历?答案是末尾的 严格小于(指非前缀) 的时候. 对于这个字符以后的前缀而言,根据我们上面的理论, 将不可能成为其最小表示. 所以,对于每一轮循环, 前面的字符串将不再有贡献,有贡献的只有 中的位置和第一个 的起始位置. 如果选择 中的位置,那么我们发现这些位置开始的循环表示其实就是第一个 中的 在当时的循环表示后面填上 ,于是答案是一样的. 注意这必须保证对应位置的 在当前考虑的串中才成立,当然如果不在那么必然更劣.
现在我们只需要解决比较两个子串. 注意由于我们上面的理论,其中一个必然是另一个的后缀,于是只需要求一个后缀和原串的 lcp,可以用 exkmp 线性求出.
IO 时间差不多占了一半#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int N=3e6+500; char st[N]; int n; int lcp[N]; int ans[N]; int chkmin(int x,int y,int r) { if(x==y)return x; int len=lcp[x+r-y+1];//cout<<len<<endl; if(len<y-x)return st[x+r-y+1+len]<st[len+1]?x:y; len=lcp[y-x+1]; if(len>=x-1)return x; else return st[len+1]<st[y-x+1+len]?x:y; } void exkmp() { lcp[1]=n;int mid=2,r=0; for(int i=2;i<=n;i++) { if(i<=r)lcp[i]=min(lcp[i-mid+1],r-i+1); else lcp[i]=0; while(i+lcp[i]<=n&&st[1+lcp[i]]==st[i+lcp[i]])++lcp[i]; if(mid+lcp[i]-1>=r)mid=i,r=mid+lcp[i]-1; } // for(int i=1;i<=n;i++)cout<<lcp[i]<<" ";puts(""); } char obuf[1<<25],*oh=obuf; inline void out(int x){ if(!x){*oh++='0';return;} static int buf[30];int xb=0; for(;x;x/=10)buf[++xb]=x%10; for(;xb;)*oh++=buf[xb--]|48; } int main() { n=fread(st+1,1,N-500,stdin);for(;!isalpha(st[n]);--n); exkmp(); for(int i=1,j,k,u;i<=n;) { j=i,k=i+1,u=1;if(!ans[i])ans[i]=i; for(;k<=n&&st[k]>=st[j];k++) { if(st[k]==st[j]) { int t=(k-i)%u+i; if(!ans[k]) { if(ans[t]<i)ans[k]=i; else ans[k]=chkmin(i,k-(t-ans[t]),k); } j++; } else { u=k-i+1;j=i;if(!ans[k])ans[k]=i; } } i+=(k-i)/u*u;//cout<<i<<endl; } for(int i=1;i<=n;++i)out(ans[i]),*oh++=' ';*oh++='\n'; fwrite(obuf,1,oh-obuf,stdout); }
- 1
信息
- ID
- 4326
- 时间
- 1000ms
- 内存
- 500MiB
- 难度
- 7
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者