题意简述
给定一个 n ( < = 1 e 9 ) n(<=1e9) n(<=1e9),构造一个序列使得:
- [ 1 , n ] [1,n] [1,n]中所有整数是这个序列中某些元素的和
- 字典序最小
输出这个序列
思路
我们一开始认为: n n n是 1 e 9 1e9 1e9,这个序列怎么也是 1 e 8 1e8 1e8,但是为什么还要输出呢?不是要 O L E OLE OLE。。。
仔细想想,并不是这样的。此时我突然想起了我们***初中初一期末考试题。和这个题一模一样,只是 n = 15 n=15 n=15。
我当时构造了一个 1 , 2 , 4 , 8 1,2,4,8 1,2,4,8。当时我的数学水平还没有现在掉的这么严重(只有全市前 100 100 100),那个时候我是前 20 20 20(我在江苏省苏州市)。对于当时做数学题经验丰富的我来说,构造这个并不难。
回忆一下当时的构造方法, 1 , 2 , 4 , 8 1,2,4,8 1,2,4,8。没错,我们只要类似“二进制拆分”就珂以了!!!所以,粗略估计答案长度是 l o g n logn logn级别的,即使 n = 1 e 9 n=1e9 n=1e9,也只有 30 30 30多一点。
但是并不是所有时候都是直接二进制拆分的,我们还要保证字典序最小。比如 n = 6 n=6 n=6的时候,应该是 1 , 2 , 3 1,2,3 1,2,3,而不是 1 , 2 , 4 1,2,4 1,2,4。这个问题很好解决,我们只要把暴力二进制拆分中的下取整改成上取整就好了。(即 ( n + 1 ) / 2 (n+1)/2 (n+1)/2)
代码:
#include<bits/stdc++.h>
using namespace std;
namespace Flandle_Scarlet
{
int n;
void Soviet()
{
int cnt=0;
int a[40];
while(n)
{
a[++cnt]=(n+1)/2;//这里改成(n+1)/2
n>>=1;
}
printf("%d\n",cnt);
sort(a+1,a+cnt+1);
for(int i=1;i<=cnt;++i)
{
printf("%d ",a[i]);
}putchar('\n');
}
void IsMyWife()
{
if (0)
{
freopen("","r",stdin);
freopen("","w",stdout);
}
cin>>n;
Soviet();
}
};
int main()
{
Flandle_Scarlet::IsMyWife();
return 0;
}
384


&spm=1001.2101.3001.11974&articleId=97612146&d=1&t=3&u=ebe32c1e5b4f458b9be50d545340607a)

被折叠的 条评论
为什么被折叠?



