题面
题解
设所有长度不超过 \(n\) 的串的集合为 \(S\)。
考虑找到一种方法,能够对一个 lyndon 串 \(A\) ,直接求出 \(A\) 的下一个 lyndon 串。方法如下:
- 先将 \(A\) 不断复制, 取出前 \(n\) 位作为新的 \(A\) ,即 \(A\leftarrow AAA⋯\) 的前 \(n\) 位。
- 如果 \(A\) 的最后一位是 \('a'+m-1\),即字符集中最大的字符,则将其删去,一直删除直到最后一位不为 \('a'+m-1\)。
- 将 \(A\) 的最后一个字符变为这个字符在字符集中的后继。(其实 2、3 操作的实质是找到 1 操作后的 \(A\) 在字典序中的下一个字符串。
设构造出的串为 \(B\)。证明这种方法的正确性,只需要证明 \(B\) 是 lyndon 串,且 \(B\) 是 \(S\) 中字典序大于 \(A\) 的最小的 lyndon 串。
-
先证 \(B\) 为 lyndon 串:
根据构造方式,设 \(A=a_1a_2⋯a_{|A|}\)。显然可以发现 \(B\) 为 \(AA⋯Aa_1a_2⋯a_x(a_{x+1}+1)\) 的形式,其中 \(1\leq x<|A|\)。由于 \(A\) 为 lyndon 串,所以对 \(\forall 1<i≤|A|\),有 \(a_ia_{i+1}\cdots a_{|A|}a_1a_2⋯a_{i−1}>a_1a_2⋯a_{|A|}\) 。
不难发现 \(B\) 的循环移位中 \(B\) 为其中的严格最小值,所以 \(B\) 为 lyndon 串。
-
再证 \(A,B\) 之间没有 \(lyndon\) 串:
如果有一个 \(S\) 中的串 \(T\) 字典序在 \(A,B\) 之间且为 lyndon 串,由构造方法可以知道 \(A<T<AAA⋯\) 。
设 \(T=AA⋯AT′\),其中 \(T'\) 的前 \(|A|\) 位不等于 AA ,显然有 \(T'<A\),则以 \(T'\) 开头的循环移位小于 \(T\) ,与 \(T\) 是 lyndon 串矛盾。
由于大部分满足条件的 lyndon 串的长度均为 \(n\),这个算法均摊复杂度为 \(O(1)\),可以 \(O(x)\) 通过此题。
代码如下:
#include<bits/stdc++.h>
#define S 35
#define N 200010
using namespace std;
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<1)+(x<<3)+(ch^'0');
ch=getchar();
}
return x*f;
}
struct Query
{
int x,id;
}q[N];
bool operator < (Query a,Query b)
{
return a.x<b.x;
}
int n,m,Q;
int len;
char s[S],Ans[N][S];
int main()
{
n=read(),m=read(),Q=read();
for(int i=1;i<=Q;i++)
q[i].x=read(),q[i].id=i;
sort(q+1,q+Q+1);
len=1;
s[0]='a';
int tmp=1;
while(tmp<=Q&&q[tmp].x==1)
{
for(int i=0;i<len;i++)
Ans[q[tmp].id][i]=s[i];
tmp++;
}
for(int i=2;i<=q[Q].x;i++)
{
int nowl=len;
while(1)
{
for(int i=0;i<nowl&&len<n;i++)
s[len++]=s[i];
if(len==n) break;
}
while(len>0&&s[len-1]=='a'+m-1) len--;
s[len-1]++;
while(tmp<=Q&&q[tmp].x==i)
{
for(int i=0;i<len;i++)
Ans[q[tmp].id][i]=s[i];
tmp++;
}
}
for(int i=1;i<=Q;i++)
{
for(int j=0;Ans[i][j];j++)
putchar(Ans[i][j]);
puts("");
}
return 0;
}
标签:AA,ch,len,1a,while,lyndon,字符串,XSY3905
From: https://www.cnblogs.com/ez-lcw/p/16841168.html