http://codeforces.com/contest/1059/problem/C
题意:给你一个n 然后代表1到n的一个序列
然后说每次进行一种操作 序列当前所有数的gcd 然后把gcd结果加入一个答案数组 然后此时可以删除序列中的一个数
重复这种操作 直至序列没有数 同时保证答案序列是字典序最大 前面的数越大越好
收获:样例一般都会 给出具有代表性 而且比较特殊的 我们应该善于发现
首先1 2 3 4 5 6 7 8 。。。n
很明显 这些数的gcd就是1
怎么删除数:可以发现这n个数中 1的倍数个数 >2的倍数个数 >3的倍数个数>4的倍数个数
所以想到了 把2的倍数保留下来 其余的删走 就是有删走个数 个1
同理 再把4的倍数保留下来 其余的删走 就是有删走个数 个2
同理 再把8的倍数保留下来 其余的删走 就是有删走个数 个4
同理 再把16的倍数保留下来 其余的删走 就是有删走个数 个8
同理 再把32的倍数保留下来 其余的删走 就是有删走个数 个16
。。。。直到没数
画了一下可以发现 每次删除的个数就是 即n - n/2 向下取整
删完每次剩余的是 没删除之前的n 除以 2 个
1 2 3 4 5 5个
2 4 2个
4 1个
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 16个
2 4 6 8 10 12 14 16 8个
4 8 12 16 4个
8 16 2个
16 1个
现在知道了 答案数组 加入的数(1 2 4 8 16。。。。)
又知道了每次删除应该 加多少个上面的数 n - n/2个
#include<iostream>
using namespace std;
const int maxn = 1e6 + 100;
int ans[maxn];
int lc;
int main(){
int n;
while (cin >> n){
// if (n == 3){
// cout << "1 1 3" << endl;
// continue;
// }
lc = 0;
//要加的数
for (int add = 1;n;add*=2){
//看样例 3 输出 1 1 3 猜的 因为1 2 3 最优不是为了保存2倍数 而删除 1 和 3 而是删除1 和 2
if (n == 3){
ans[lc++] = add, ans[lc++] = add, ans[lc++] = add * 3;
break;
}
int many = n - n/2;//删除的个数 加上删除个数 个 add
for (int j = 0; j < many; ++j){
ans[lc++] = add;
}
n = n / 2;//更新序列
}
for (int i = 0; i < lc;++i){
cout << ans[i] << " ";
}
cout << endl;
}
return 0;
}
官方题解是利用 每次删除都是 奇数位
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 6;
int seq[maxn];
int ans[maxn];
int ptr = 0;
void solve(int n, int mul){
if(n == 1){ans[ptr++] = mul; return;}
if(n == 2){ans[ptr++] = mul; ans[ptr++] = mul * 2; return;}
if(n == 3){ans[ptr++] = mul; ans[ptr++] = mul; ans[ptr++] = mul * 3; return;}
for(int i = 0; i < n; i++)if(seq[i]&1)ans[ptr++] = mul;
for(int i = 0; i < n/2; i++)seq[i] = seq[2*i + 1]/2;
solve(n/2, mul * 2);
}
int main(){
int n;
scanf("%d", &n);
for(int i = 0; i < n; i++)seq[i] = i + 1;
solve(n, 1);
for(int i = 0; i < n; i++)printf("%d ", ans[i]);
return 0;
}