ARC163C(裂项构造 + 思维) 600

ARC163C(裂项构造 + 思维) 600

大意:一个数N , 要求构造长度为 N 的数列 A , 满足

1. 任意两个数互不相同 , 且

2.

∑ 1 N 1 A i = 1 \sum_{1}^{N} \frac{1}{A_i} = 1 1NAi1=1

3.

( 1 < = A i < = 1 e 9  且  1 < = N < = 500 ) (1 <= A_i <= 1e9 \space且\space 1<=N<=500) (1<=Ai<=1e9  1<=N<=500)

思路:这里我们借助一个裂项的公式:

1 n − 1 n + 1 = 1 n ∗ ( n + 1 )        ( 1 ) \frac{1}{n} - \frac{1}{n+1} = \frac{1}{n*(n+1)} \space\space\space\space\space\space(1) n1n+11=n(n+1)1      (1)

1 = 1 − 1 2 + 1 2 − 1 3 + 1 3 − . . . + 1 n       ( 2 ) 1 = 1 - \frac{1}{2} + \frac{1}{2} - \frac{1}{3} + \frac{1}{3} - ... + \frac{1}{n}\space\space\space\space\space(2) 1=121+2131+31...+n1     (2)

1 = 1 1 ∗ 2 + 1 2 ∗ 3 + . . . + 1 ( n − 1 ) ∗ n + 1 n        ( 3 ) 1 = \frac{1}{1*2} + \frac{1}{2*3}+...+\frac{1}{(n-1)*n}+\frac{1}{n}\space\space\space\space\space\space(3) 1=121+231+...+(n1)n1+n1      (3)

发现了这个裂项公式之后就很好去处理。需要注意的是处理特殊情况 当:

n = ( t − 1 ) ∗ t      ( t > = 2 ) n = (t - 1) * t \space\space\space\space (t >= 2) n=(t1)t    (t>=2)

这时可能会出现两个相同的项 , 这时 , 由于 n 一定是个偶数 , 我们可以合并两个相同的项再去裂项 。这样可以在不改变项的数目的前提下使得任意两项不同。 即对下面的项再使用裂项公式 (4)

1 n 2 \frac{1}{\frac{n}{2}} 2n1

1 n = 1 n ∗ ( n + 1 ) + 1 n + 1        ( 4 ) \frac{1}{n} = \frac{1}{n*(n+1)} + \frac{1}{n+1} \space\space\space\space\space\space(4) n1=n(n+1)1+n+11      (4)

这时 n * (n + 1) 一定为偶数 , 可能与前面某项相同 , 递归合并裂项即可。

对于 (n + 1) 若为 奇数 , 由于前面构造的项都是偶数 , 递归合并裂项的奇数项一定是单调递增的 ,所以奇数项不会冲突

若为 偶数 , 可能与前面某项相同 , 若相同执行递归合并裂项操作即可

注意 n = 2 的时候递归会死循环 , 也是唯一的 NO 的情况 , 特判即可

#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define IOS std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define int long long
const int N = 2e5+10;
const int mod = 1e9 + 7;
typedef pair<int,int>PII;
const int inf = 1 << 31 - 1;
const double eps = 1e-9;

int t , n ;
set<int>st;

void check(int x){
	
	st.erase(x);
	x /= 2;
	
	if(st.find(x + 1) == st.end()){
		st.insert(x + 1);
	}else{
		check(x + 1);
	}
	
	if(st.find(x * (x + 1)) == st.end()){
		st.insert(x * (x + 1));
	}else{
		check(x * (x + 1));
	}
}

signed main(){

	cin >> t;
	
	
	while(t--){
		
		cin >> n;
		st.clear();
		
		if(n == 2){
			cout << "No\n";
			continue;
		}
		
		for(int i=1;i<=n-1;i++) st.insert(i * (i + 1));
		
		if(st.find(n) == st.end()){
			st.insert(n);
		}else{
			check(n);
		}
		
		
		cout << "Yes\n";
		for(auto k : st) cout << k << " ";
		cout << "\n";
		
		
	}
	

	return 0;
}
//freopen("文件名.in","r",stdin);
//freopen("文件名.out","w",stdout);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

.Ashy.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值