ARC163C(裂项构造 + 思维) 600
大意:一个数N , 要求构造长度为 N 的数列 A , 满足
1. 任意两个数互不相同 , 且
2.
∑ 1 N 1 A i = 1 \sum_{1}^{N} \frac{1}{A_i} = 1 1∑NAi1=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) n1−n+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=1−21+21−31+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=1∗21+2∗31+...+(n−1)∗n1+n1 (3)
发现了这个裂项公式之后就很好去处理。需要注意的是处理特殊情况 当:
n = ( t − 1 ) ∗ t ( t > = 2 ) n = (t - 1) * t \space\space\space\space (t >= 2) n=(t−1)∗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);