暑期个人赛--第七场--B

时间限制 1000 ms  内存限制 65536 KB

题目描述

现有正整数集A={i|i>0&&i<=n},求A的子集合B,使得对于任意x属于B,y属于B,x整除y或y整除x。优先考虑所含元素多的子集合,然后优先考虑所含元素和大的子集合,然后优先考虑字典序小的子集合。

输入格式

每组数据包含一行一个整数n(n<1e5).输入以EOF结束。

输出格式

每组数据输出一行,从小到大输出所求集合,注意行尾不要有空格。

输入样例

6
100

输出样例

1 3 6
1 3 6 12 24 48 96



赛中提交:AC


题目大意:

给出整数n,要求求出尽可能长和尽可能大的符合“其中任意两个数xy,x整除y或者y整除x”的序列,

再按照升序输出

其中优先保证尽可能长,才保证和尽可能大


思路:

其实就是在“小于n的,可以被质因数分解得最多的整数”中找出和最大的那个

首先,必须是会有一的 ,

接着,由于这个序列的最大值必须小于n,所以我们可以注意到

当一个整数约小于n/5时,这个时候我们可以把5当做下一个质因数,或者是3或者是2

这个时候序列长度都是一样的,但是用2,3,5在加和时的新加的部分分别是

(2+2*2)x,3x或者(3+3*3)x,和5x

显而易见,任何时候选择2,3都比5更优,所以我们在递归时只需要考虑质因数为2,3即可



下面是AC代码


#include <iostream>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string>
#include <vector>
#include <list>
#include <map>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <numeric>
#include <functional>
#define maxn 500005
 
using namespace std;
int n;
int choice[3]={2,3,5};
int maxd,maxsum;
int ans[20]={0};
 
void cop(int res[])
{
    for(int i=0;i<=maxd;i+=1){
        ans[i]=res[i];
    }
}
 
void dfs(int a,int depth,int sum,int res[])
{
    //printf("(a=%d,depth=%d,sum=%d)\n",a,depth,sum);
    if(a>n){
        if(depth-1>maxd){         //深度优先就是个数优先
            maxd=depth-1;
            maxsum=sum-a;
            cop(res);
            return ;
        }
        else if(depth-1==maxd&&sum-a>maxsum){    //其次加和优先
            maxd=depth-1;
            maxsum=sum-a;
            cop(res);
            return ;
        }
        return ;
    }
 
    for(int i=0;i<3;i+=1){
        res[depth]=a;
        dfs(choice[i]*a,depth+1,sum+choice[i]*a,res);
    }
}
 
int main()
{
    while(scanf("%d",&n)!=EOF){
        int /*ans[20]={0},*/res[20]={0};
        /*ans[0]=1,*/res[0]=1;
        maxd=-1,maxsum=-1;
        dfs(1,0,1,res);
 
        for(int i=0;i<=maxd;i+=1){
            printf("%d",ans[i]);
            if(i!=maxd){
                printf(" ");
            }
            else{
                printf("\n");
            }
        }
    }
 
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值