• 51nod 2538 二三排列


    题目链接:http://class.51nod.com/Course/Problem.html#courseProblemId=1328

    一、题目描述

    给你 n个正整数,请你将其重排,使得后一个数是前一个数的三分之一(整除)或二倍。

    你只需判断是否有解,若有解,输出 Possible ,否则输出 Impossible 。

    n≤106,所有数字 1018

    输入描述

    第一行一个数字 n 。
    第二行 n 个数字。

    输出描述

    一行一个字符串。若有解,输出 Possible ,否则输出 Impossible 。

    样例输入

    3
    3 1 2

    样例输出

    Possible

    二、解题思路

    我们从一个数的质因子角度去考虑,2,3本就是两个相互独立的质因子。

    每次对其×2,意味着质因子2的指数+1,每次对其/3,意味着质因子3的指数-1。

    这种单调的变化可以引起我们的一些思考。

    考虑一个数x,如果数列中既有x×2又有x/3,那么你任选其一,则另外一个就再也无法通过操作得到了。

    因此这种情况一定是无解的。

    因此不难想到,我们找到每一个数的“后继”,再检查所形成的结构是不是一条链就可以了。

    ——————————————————————————————————————————————————

    我们发现可以看每个输入的数据等于几个2相乘等于几个3相乘

    a[i].first存的是输入的数据等于几个2相乘

    a[i].second存的是输入的数等于几个3相乘

    a[i]数组是pair类型的,pair类型可以将两个量配成一组,正好可以利用到这道题里面。

    例如我下面列的表格:

    代码的话得加上这个头文件:#include<pair>,如果使用万能头文件的话就不用了

    排序前数字
    x(输入进来的数) a[i].first a[i].second
    3 0 -1
    1 0 0
    2 1 0
    4 2 0
    8 3 0
    16 4 0
    36 2 -2
    12 2 -1
    72 3 -2

    我们肯定需要将输入的数进行排序来决定最后的顺序。

    排序原则:先按照升序排列first,如果first一样,按照升序排列second

    排序后数字
    x(输入进来的数) a[i].first a[i].second
    3 0 -1
    1 0 0
    2 1 0
    36 2 -2
    12 2 -1
    4 2 0
    72 3 -2
    8 3 0
    16 4 0

    此外,还有两个点需要注意:

    ①如果我输入的数据发现除完2而且也除完3了,还剩下一个数字。

      (这个数不可能是2或者3,有可能是5这种数字,在代码里面设置为c1)。

     那么最后不管怎么排序肯定是不行的

    ②如果我输入的数据发现排完序后相邻的两个数还是没有任何一种连接

     最后肯定也是不行的

       (在代码里我用了c和d这两个变量来判断)

    三、代码

    #include<map>
    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    pair <int,int> a[1000005];
    
    bool check(){
        long long n, c1=0, x, c, d;
        cin >> n;
        if(n >= 60*60){//如果数据太大不能计算 
            return 0;
        }
        //a[1]=2^x*3^y*c1,其中c1%2>0,c1%3>0 
        for(int i = 1;i <= n;i++){
            cin >> x;//输入数据 
            while(x % 2 == 0){//如果是2的倍数 
                x /= 2;//x要除以二 
                ++a[i].first;//在存x能分为几个2相乘的地方+1 
            }
            while(x % 3 == 0){//如果是3的倍数 
                x /= 3;//x要除以三 
                --a[i].second;//这里是--因为待会在算c和d的时候好算 
            }
            if(i == 1){//如果是第一次输入数据 
                c1 = x;//c1=剩下的数 
            }else if(c1 != x){//如果有一次输入的数除完2除完3后剩下的数不是c1了
                //答案肯定不行 
                return 0;//如果输入3 1 2 5就return0 
            }
        }
        sort(a+1,a+n+1);//进行排序 
        for(int i = 2;i <= n;i++){
            c = a[i].first - a[i-1].first;//c为相邻的两个数能分解成几个2相乘的差 
            d = a[i].second - a[i-1].second;//d为相邻的两个数能分解成几个3相乘的差 
            if(!(c >= 0 && d >= 0 && c+d == 1)){//如果输入3 1 2 8就return0 
                return 0;
            }
        }
        return 1;
    }
    int main(){
        puts(check()?"Possible":"Impossible");
        return 0;
    }
  • 相关阅读:
    windows7通过Dns.GetHostAddresses(Dns.GetHostName())获得ipv6地址转换到ipv4
    题解 P3829 【[SHOI2012]信用卡凸包】
    点积与叉积
    点分治
    珂朵莉树
    NOIP2020模拟赛(二十五)7.26 结题报告
    树连剖分
    NOIP2020模拟赛(拾)解题报告
    题解 P2538 【[SCOI2008]城堡】
    模拟退火
  • 原文地址:https://www.cnblogs.com/elisa02/p/12907123.html
Copyright © 2020-2023  润新知