序列重排

序列重排

给定一个长度为 $n$ 的整数序列 $a_{1},a_{2}, \dots ,a_{n}$。

请你对序列进行重新排序(也可以保持原序列),要求新序列满足每个元素(第 $1$ 个除外)都恰好是前一个元素的两倍或前一个元素的三分之一。

保证输入一定有解。

输入格式

第一行包含整数 $n$。

第二行包含 $n$ 个整数 $a_{1},a_{2}, \dots ,a_{n}$。

输出格式

一行 $n$ 个整数,表示排序后的序列。输出任意合法方案即可。

数据范围

前三个测试点满足 $2 \leq n \leq 10$。
所有测试点满足 $2 \leq n \leq 100$,$1 \leq a_{i} \leq 3 \times {10}^{18}$。

输入样例1:

6
4 8 6 3 12 9

输出样例1:

9 3 6 12 4 8 

输入样例2:

4
42 28 84 126

输出样例2:

126 42 84 28

输入样例3:

2
1000000000000000000 3000000000000000000

输出样例3:

3000000000000000000 1000000000000000000

 

解题思路

  首先这题保证有解。假设有满足题目要求的序列$a_{1}~~a_{2}~\dots~a_{n}$。用$x_{i}$来表示第$i$个数的因子$2$的数量,用$y_{i}$来表示第$i$个数的因子$3$的数量。

  在这个序列中除了第$1$个数外,对于第$i$个数,要么$a_{i}$是$a_{i-1}$的两倍,即$x_{i}$比$x_{i-1}$多$1$;要么$a_{i}$是$a_{i-1}$的$\frac{1}{3}$,即$y_{i}$比$y_{i-1}$少$1$。因此可以发现,对于任意一个数,它要么比前一个数的因子$2$多$1$,要么与前一个数的因子$2$数量相同。因此有$x_{i} \leq x_{i+1}$,即数列$x_{i}$是递增的。

  如果某一个数与它前一个数的因子$2$的数量相同,即$x_{i} = x_{i-1}$,由于这是一个合法的序列,因此必然有这个数的因子$3$数量比前一个数的少$1$,即$y_{i} = y_{i-1} - 1$。

  因此我们可以得到一个必要条件,就是如果这是一个合法序列,那么必然有($x_{i} < x_{i+1}$)或者($x_{i} = x_{i+1}$且$y_{i} > y_{i+1}$)。这是一个必要条件,也就是说如果是一个合法序列那么这个序列一定满足这个必要条件。而如果某个序列满足必要条件,那么这个序列不一定是一个合法序列。

  由于保证有解,因此对于任何一个序列重新排完序后,满足这个必要条件的序列是唯一的。下面来证明。

  首先不会有任何两个数$a_{i}$,$a_{j}$的因子$2$数量和因子$3$的数量相同,即$x_{i} = x_{j},~ y_{i} = y_{j}$。反证法,假设存在这个情况的话,首先$i,~ j$必然会是这个合法序列中的某两个位置,假设这两个数之间的数有$a_{i}~~a_{k_{1}}~~a_{k_{2}}~\dots~a_{j}$,因为这是一个合法序列,因此有$x_{i} \leq x_{k_{1}} \leq x_{k_{2}} \leq \dots \leq x_{j}$,由于$x_{i} = x_{j}$,因此中间所有数的因子$2$数量相等,即$x_{i} = x_{k_{1}} = x_{k_{2}} = \dots = x_{j}$。因为是合法序列,因子$2$的数量都相等,因此必然会有$y_{i} > y_{k_{1}} > y_{k_{2}} > \dots > y_{j}$,这就与$y_{i} = y_{j}$矛盾了。因此结论是如果要使序列可以变成合法序列,那么一定不会存在两个数的因子$2$和因子$3$的数量分别相等。因此序列中任何两个数的$x_{i}$和$y_{i}$不相等,根据双关键字排序,由于任何两个数都不会相等(即同时满足$x_{i} = x_{j},~ y_{i} = y_{j}$),因此每个数都有严格的大小顺序,因此他们排完序后的结果是唯一的。

  所有,由于序列是有解的,因此不存在有两个数的因子$2$和因子$3$数量都分别相等,因此可以构造出一个满足必要条件的合法的序列,并且满足这个必要条件的序列是唯一的。

  假设合法的序列是$S$。我们根据双关键字排序后得到一个序列$S_{1}$,这个序列满足必要条件,但不一定是合法的序列。又因为满足必要条件的序列是唯一的,因此$S_{1}$就是$S$。这是因为$S$满足必要条件,$S_{1}$也满足必要条件,因为一个序列满足必要条件不一定满足充分条件,但因为满足必要条件的序列是唯一的,因此满足必要条件的序列也会满足充分条件。

  AC代码如下:

 1 #include <cstdio>
 2 #include <vector>
 3 #include <algorithm>
 4 using namespace std;
 5 
 6 typedef long long LL;
 7 
 8 const int N = 110;
 9 
10 vector<LL> a[N];
11 
12 int get(LL n, int b) {
13     int ret = 0;
14     while (n % b == 0) {
15         ret++;
16         n /= b;
17     }
18     return ret;
19 }
20 
21 int main() {
22     int n;
23     scanf("%d", &n);
24     for (int i = 0; i < n; i++) {
25         LL val;
26         scanf("%lld", &val);
27         a[i] = {get(val, 2), -get(val, 3), val}; // 因为第二关键字要升序,因此乘个负号
28     }
29     
30     sort(a, a + n);
31     
32     for (int i = 0; i < n; i++) {
33         printf("%lld ", a[i][2]);
34     }
35     
36     return 0;
37 }

 

参考资料

  AcWing 4211. 序列重排(AcWing杯 - 周赛):https://www.acwing.com/video/3668/

posted @ 2022-04-01 20:25  onlyblues  阅读(264)  评论(0编辑  收藏  举报
Web Analytics