B

【题目描述】

给定k,你需要找到一个最小的n,使得有至少一个1~n的排列不是任何一个字符集不超过k的字符串的后缀排名数组,并构造出这样的排列中字典序最小的一个。

后缀排名数组指:对于一个字符串,将其所有后缀按字典序排序,第i的后缀排名为a[i]。如abbab的后缀排名数组为 2 5 4 1 3。

【输入】

一行一个正整数k。

【输出】

输出包含两行。第一行为n,第二行为一个1~n的排列满足题目条件。

【输入样例】

2

【输出样例】

3
2 1 3

【提示】

长为2的字符集不超过2的字符串有aa,ab,ba。后缀排名数组分别为2 1,1 2,2 1。包含了所有的排列。长为3的字符集不超过2的字符串有aaa,aab,aba,abb,baa,bab,bba。后缀排名数组分别为3 2 1,1 2 3,2 3 1,1 3 2,3 2 1,3 1 2,3 2 1。因此2 1 3是符合条件的解。

 

对于20%的数据点,1<=k<=10;

对于50%的数据点,1<=k<=1000;

对于100%的数据点,1<=k<=100000。

发现当n <= k的时候一定存在合法序列,考虑n = k + 1

我们要使每个位置的字母都不相同,这样即不合法。

即对于位置 a 和 b,a + 1 和 b + 1 与 a 和 b 之间的大小关系应该相反。

否则就可以令 a 和 b 为同一字符。

然后考虑n,显然任何数都比它小,所以它后面应该是最小的:0,所以放最后。

考虑1,显然任何数都比它大,所以它后面应该是最大的:n

然后交替倒推即可构造。

 1 #include <cstdio>
 2 const int N = 100010;
 3 
 4 int a[N];
 5 
 6 int main() {
 7     int n;
 8     scanf("%d", &n);
 9     n++;
10     printf("%d\n", n);
11     int t = n + 1;
12     for(int i = n; i > 0; i -= 2) {
13         a[i] = --t;
14     }
15     for(int i = a[1] ? 2 : 1; i <= n; i += 2) {
16         a[i] = --t;
17     }
18     for(int i = 1; i <= n; i++) {
19         printf("%d ", a[i]);
20     }
21     return 0;
22 }
AC代码

关于字典序最小,据说可以证明这样构造出来的是 n = k + 1 时的唯一解。不会。

 

posted @ 2018-07-31 16:10  huyufeifei  阅读(208)  评论(1编辑  收藏  举报
试着放一个广告栏(虽然没有一分钱广告费)

『Flyable Heart 応援中!』 HHG 高苗京铃 闪十PSS 双六 電動伝奇堂 章鱼罐头制作组 はきか 祝姬 星降夜