B. 最长数链 2014新生暑假个人排位赛07
时间限制 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;
}