注:作者并不熟悉字符串相关知识,所以不知道下面的证明的表述是否严谨,是否为伪证,请各位大佬帮忙看下其正确性/kk
以下将字符串 s 的前缀 s[1..n] 称为 prefix(n),将字符串 s 无限连接自身构成的字符串的前 k 个字符称为 fk(s),即 fk(s)={s[1..k] (∣s∣≥k)fk(s+s) (∣s∣<k)。
将题意转化为求 fk(prefix(x)) 最小的 x,有一种贪心做法如下:
枚举前缀的结尾位置 i ,设当前找到的最优前缀为 pos ,fk(prefix(pos))[i] 为 t,比较 s[i] 与 t 的大小关系,有如下三种情况:
s[i]>t,此时由于 i 以后的每个位置的前缀都会包含 s[i],所以 i 以后不会有更优解,因此直接退出循环。
s[i]<t,此时若有 s[1..i−1]=fk(prefix(pos))[1..i−1] ,则此时 i 优于 pos,更新答案。反证一下满足条件,按上述方式循环,若 s[1..i−1]>fk(prefix(pos))[1..i−1],则在 i−1 或更早的位置就已退出循环;若 s[1..i−1]<fk(prefix(pos))[1..i−1],则不符合 pos 是最优解的定义。故 s[1..i−1]=fk(prefix(pos))[1..i−1],满足更新答案的条件。
s[i]=t,此时直接继续枚举 i+1。@九九九九 大佬的题解中提出该做法有被 hack 的可能性,但 fk(prefix(i))[i+1]=s[1],fk(prefix(pos))[i+1]=s[(imodpos)+1],不难得到 s[(imodpos)+1]≤s[1],因为若 s[(imodpos)+1]>s[1],则我们直接在此处填 s[1] 会更优,不符合 pos 是最优解的定义,同理 fk(prefix(i)) 与 fk(prefix(pos)) 的第 i+2,i+3,⋯,k 个字符也可按上述方式比较大小关系。因此 i 不会比 pos 更优,但继续枚举下去可能会有更优解。
相关代码:
#include<bits/stdc++.h>
using namespace std;
#define ri register int
#define x (i-1)%pos+1
const int maxn=5e5+10;
int m,n;
char t[maxn];
int main(){
scanf("%d%d%s",&n,&m,t+1);
ri k=min(m,n),pos=1;
for(ri i=2;i<=k;++i)
if(t[i]<t[x])pos=i;
else if(t[i]>t[x])break;
for(ri i=1;i<=m;++i)putchar(t[x]);
return 0;
}
(如果有显然的错误就当我是**