Description
给定 \(k\),要找到一个最小的正整数 \(n\) 使得存在 \(1 \sim n\) 的一个全排列,它不是任何一个字符集大小不超过 \(k\) 的字符串的后缀排名数组。输出 \(n\) 以及一个合法的全排列。
Solution
神仙构造。整体思路是让奇偶位的顺序颠倒。
举个例子,\(k=5\) 时,我们取 \(n=6\),则
sa[] = {5, 3, 1, 2, 4, 6}
rk[] = {3, 4, 2, 5, 1, 6}
考虑所有后缀的首位,显然至少有两个是相等的,并且它们一定可以是在后缀排序中相邻的。
假如 \(a[5]=a[3]\),则根据 \(s[5:]<s[3:]\),一定有 \(s[4:]<s[6:]\),但由已知 \(s[6:]<s[4:]\),矛盾。
以此类推,即可证明正确性,即总是存在一个 \(1 \to k+1\) 的全排列,使得它不是任意一个字符集大小不超过 \(k\) 的字符串的后缀排名数组。
考虑最小性,对于 \(n=k\),显然我们可以随意构造,同理可知 \(n \le k\) 均不可。
综上,\(n=k+1\),构造方式即类似 rk[] = {3, 4, 2, 5, 1, 6} 这样的操作。
#include <bits/stdc++.h>
using namespace std;
const int N = 100005;
int n,k,a[N];
signed main()
{
cin>>k;
n=k+1;
cout<<n<<endl;
int i=n,x=1,y=n;
while(i>0)
{
a[i--]=y--;
a[i--]=x++;
}
for(int i=1;i<=n;i++) cout<<a[i]<<" ";
}