mltang

博客园 首页 新随笔 联系 订阅 管理

题目大意:给你一个n

从1,2,3......n这个序列中

依次进行以下操作:1 、求所有数的最大公因数,放入a序列里面

         2 、任意删去一个元素

 

         一直到序列为空

 

根据删除元素的不同,导致序列a的字典序可能不同

输出字典序最大的a序列

 

 

看到这题,首先我想到gcd的两个特性,首先gcd(a1,a2,a3,a4.....an)  <= min(a1,a2,a3,a4...an);

其次  任意两个相邻的数  gcd等于1   gcd(4,5) == 1

 

回过头看序列  1  ,2   , 3  ,  4  ,5  ,6  ,7  ,8 

先举例8个数   首先,你这个开头的1不删除,你的gcd永远不可能超过1,所以我的第一个删除的原属就是这个1

其次,相邻两个数gcd等于1,为了让gcd尽早的大于1,那么对于3,5,7,我们都应该删除(这时候不能删除2,4,6,8,原因你可以自己思考)

那么就删除3,5,7这3个元素

序列中生下了2,4,6,8这4个元素

这时gcd == 2,那么你这个2不删的话,你的gcd永远不可能大于2,所以这个2,是要首先删除的,

剩下4,6,8这三个元素,类比上面的删除中间元素,删除6

剩下两个元素4,8 ,当序列中只剩下两个元素的时候,先输出两个数gcd,然后输出最大的数即可

总结一下就是:删除1,3,5,7。。。。。

       删除2,6,10 ,14 。。。。。

       删除4 ,12,20,28 .。。。。

 

当然上面讨论的都是偶数的情况,奇数的情况是否使用呢?

交给判题姬判断吧

 

其实奇数的情况和偶数的情况是一样的,无非就是1,2,3,4,5

删除1,剩下2,3,4,5

那么删2,4还是删3,5

推了几个例子发现删3,5比较好

#include<iostream>
#include<queue>
#include<algorithm>
#include<cstring>
#include<vector>
#include<cstdio>
#include<cmath>
#include<map>
#include<set>
#include<string>
using namespace std;
#define ll long long
#define se second
#define fi first
#define oo 0x3fffffff
int arr[1000005];
vector<int> q;
set<int> s;
int gcd(int a,int b)
{
    return b == 0? a:gcd(b,a%b);
}
int main()
{
    int n;
    scanf("%d",&n);
    for(int i = 1; i <= n; ++i)
    {
        arr[i] = i;
        s.insert(i);
    }
    if(n == 1)
    {
        printf("1\n");
        return 0;
    }
    //if(n%2 == 0)
    //{
        int cnt = n;
        int ans = 1;
        while(s.size() != 2)
        {
            for(int i = ans; i <= n && s.size() != 2; i+=ans*2)
            {
                //cout << i << endl;
                printf("%d ",ans);
                s.erase(i);
            }
            ans *= 2;
        }
        set<int>::iterator it;
        it = s.begin();
        //it ++;
        cout << gcd(*it,*(it++)) << " " ;
        cout << *it << endl;
    //}
    return 0;
}

 

posted on 2018-10-06 12:58  mltang  阅读(158)  评论(0编辑  收藏  举报