CF C. Sequence Transformation【规律】

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;
}

猜你喜欢

转载自blog.csdn.net/liangnimahanwei/article/details/82949388