codeforces 977D Divide by three, multiply by two

题目

Polycarp likes to play with numbers. He takes some integer number x , writes it down on the board, and then performs with it n1

operations of the two kinds:

  • divide the number x by 3 (x must be divisible by 3 );
  • multiply the number x by 2.

After each operation, Polycarp writes down the result on the board and replaces x by the result. So there will be n numbers on the board after all.

You are given a sequence of length n — the numbers that Polycarp wrote down. This sequence is given in arbitrary order, i.e. the order of the sequence can mismatch the order of the numbers written on the board.

Your problem is to rearrange (reorder) elements of this sequence in such a way that it can match possible Polycarp’s game in the order of the numbers written on the board. I.e. each next number will be exactly two times of the previous number or exactly one third of previous number.

It is guaranteed that the answer exists.

Input
The first line of the input contatins an integer number n (2n100) — the number of the elements in the sequence. The second line of the input contains n integer numbers a1,a2,,an ( 1ai31018 ) — rearranged (reordered) sequence that Polycarp can wrote down on the board.

Output
Print n integer numbers — rearranged (reordered) input sequence that can be the sequence that Polycarp could write down on the board.

It is guaranteed that the answer exists.

Examples

Input
6
4 8 6 3 12 9
Output
9 3 6 12 4 8

Input
4
42 28 84 126
Output
126 42 84 28

Input
2
1000000000000000000 3000000000000000000
Output
3000000000000000000 1000000000000000000

Note
In the first example the given sequence can be rearranged in the following way: [9,3,6,12,4,8]. It can match possible Polycarp’s game which started with x=9 .

分析

【题意】
有一个原始串 a[n] ,每一位都满足下列的其中一个条件

  • a[i+1]=a[i]2
  • a[i+1]=a[i]/3 a[i] 必须整除3)

现在用打乱的顺序给出该串,输出原串。

【思路】
每个点有两种转移情况,而且转移不可逆,可以放到有向图上思考:给一个含有n个点,最多2*n条边的有向图,找出一条经过所有点的路径。暴力搜索一遍表面上看似有 2n 种情况,但其实对于每个点的搜索,它最多就把 n 个点访问一遍,也就是n次,所以对 n 个点全部搜索一遍总共不会超过n2次。

【注意】
搜索结束的控制:只有把所有的点不重复的遍历一次后,才算成功:保证遍历不重复的同时,在搜索中增加一维来记录已经遍历过的个数;
边的存在不是明显的,需要检查下一次要搜索的数是否存在,用二分检索以降低复杂度。

代码

#include<stdio.h>
#include<vector>
using std::vector;

#define N_max 105
typedef unsigned long long ll;
int g[N_max][N_max];
ll ipt[N_max];
int n;
vector<int>vis;
#define debug no_bug_at_all
ll ans[N_max];
int dfs(ll cur,int tot) {
    if (tot > n)return 1;
    //二分检查cur是否存在
    int l = -1, r = n,m;
    while (l+1 < r) {
        m = (l + r) / 2;
        if (ipt[m] <= cur)l = m;
        else r = m;
    }
    //不存在
    if (l == -1)return 0;  
    if(ipt[l] != cur)return 0;
    //已经访问过
    if (vis[l] == 1)return 0;
    //标记访问位置
    vis[l] = 1;
    if (cur % 3 == 0)
        if (1 == dfs(cur / 3, tot+1))
        {
            ans[tot] = cur;
            return 1;
        }
    if (1 == dfs(cur * 2, tot+1)) {
        ans[tot] = cur;
            return 1;
    }
    else { 
        vis[l] = 0;
        return 0; 
    }
}
int main() {

    scanf("%d", &n);
    for (int i = 0; i < n; ++i) 
        scanf("%llu", &ipt[i]);
    //排序以二分查找
    sort(ipt, ipt + n);
    for (int i = 0; i < n; ++i) {
         vis.resize(n);
         if (1 == dfs(ipt[i], 1))
         {
             for (int i = 1; i <= n; ++i) {
                 printf("%llu%c", ans[i], i == n? '\n' : ' ');
             }
             return 0;
         }
    }
}

总结

其实题目中的数字一定是非重复的,使用vis数组不仅没有意义,而且另一方面,假如有重复的,vis数组将会带来错误。考虑对重复数字的改进,可以对输入进行预处理,把重复的数字的个数记录到cnt数组,同时保证剩下的数没有重复;另一方面,搜索时要判断是否还有可用的数可以用(cnt[x]>0),每遍历到这个数字,就让cnt[x]–。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值