codeforces round 514div2C Sequence Transformation(思维+找规律)

题意

给出一个长度为 n n n的序列,初始序列为 1 , 2 , 3 , … , n 1,2,3,\dots,n 1,2,3,,n,每次计算出当前序列的 G C D GCD GCD并输出,然后可以任意删除序列中的一个数,重复前面操作,直到整个序列为空。要求输出的 G C D GCD GCD序列字典序最大。

乱搞题解

很明显最后的GCD序列长度是 n n n,通过手算几个样例我发现了当 n > 3 n > 3 n>3时一个规律,输出的GCD都是 2 i 2^i 2i,每4个 2 i 2^i 2i出现的次数是 c n t = n − 2 i 2 i + 1 + 1 cnt = \frac{n-2^i}{2^{i+1}}+1 cnt=2i+1n2i+1,当 i = = 0 i == 0 i==0 n n n为奇数时, c n t + 1 cnt+1 cnt+1其余的时候可以当做 n − 1 n-1 n1处理 。但这个需要特殊处理一下最后一次的GCD,最后的数字是 n / l a s t ( 2 i ) ∗ l a s t ( 2 i ) n/last(2^i)*last(2^i) n/last(2i)last(2i) l a s t ( 2 i ) last(2^i) last(2i)代表的是在 n − 1 n-1 n1处出现的 2 i 2^i 2i

正规题解

可以发现一开始需要删除掉全是奇数的数字 c n t cnt cnt个,输出 c n t cnt cnt个1,之后剩下的都是 2 , 4 , 6 , 8 , … 2,4,6,8,\dots 2,4,6,8,的序列,这相当于 1 , 2 , 3 , 4 , … 1,2,3,4,\dots 1,2,3,4,乘一个2,所以问题还是和前面一样,删除下标为奇数的数字 c n t cnt cnt个,然后输出最前面的那个数字 c n t cnt cnt个。
然后不断将问题缩小,当 n ≤ 3 n \leq 3 n3时要特殊处理一下。

乱搞代码

#include <bits/stdc++.h>
using namespace std;
int gcd(int a,int b) {
	return b == 0 ? a: gcd(b,a%b);
}
int main() {
	int n;
	scanf("%d", &n);
	int cnt = 0;
	if(n <= 3) {
		if(n == 3)
			cout <<"1 1 3" << endl;
		if(n == 2)
			cout << "1 2" << endl;
		if(n == 1)
			cout << 1 << endl;
		return 0;
	}
	int last;
	int sum = 0;
	int p = 1;
	sum++;
	cout << p << " ";
	last = p;
	int f = 2;
	int t = n;
	while((n-p)/f > 0) {
		int cnt = (n-p)/f;
		if(n&1) n--;
		for(int i = 0; i < cnt; ++i)
			cout << p <<" ";
		sum += cnt;
		last = p;
		p *= 2; f *= 2;
		if(sum < t-1) {
			sum++;
			cout << p <<" ";
			last = p;
		}
	}
	cout << n/last*last << 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值