题目大意
给你一个正整数 n n n,求是否有存在长度为 n n n的序列 A A A,满足
- ∑ i = 1 n 1 A i = 1 \sum\limits_{i=1}^n\dfrac{1}{A_i}=1 i=1∑nAi1=1
- A i A_i Ai互不相同
- 1 ≤ A i ≤ 1 0 9 1\leq A_i\leq 10^9 1≤Ai≤109
如果有,就输出 Y e s Yes Yes,并输出序列 A A A;如果没有,就输出 N o No No。
有 t t t组数据。
1 ≤ t ≤ 500 , 1 ≤ n ≤ 500 1\leq t\leq 500,1\leq n\leq 500 1≤t≤500,1≤n≤500
题解
首先,我们知道 1 a − 1 a + 1 = 1 a ( a + 1 ) \dfrac{1}{a}-\dfrac{1}{a+1}=\dfrac{1}{a(a+1)} a1−a+11=a(a+1)1,那么
1 = 1 − 1 2 + 1 2 − 1 3 + ⋯ − 1 n + 1 n = 1 2 + 1 6 + ⋯ + 1 ( n − 1 ) ⋅ n + 1 n 1=1-\dfrac 12+\dfrac 12-\dfrac 13+\cdots-\dfrac{1}{n}+\dfrac 1n=\dfrac 12+\dfrac16+\cdots+\dfrac{1}{(n-1)\cdot n}+\dfrac 1n 1=1−21+21−31+⋯−n1+n1=21+61+⋯+(n−1)⋅n1+n1
因为 1 ≤ n ≤ 500 1\leq n\leq 500 1≤n≤500,所以 1 ≤ n ( n − 1 ) ≤ 250000 1\leq n(n-1)\leq 250000 1≤n(n−1)≤250000,满足第三个条件,这样就可以得到一个 A A A序列。
但如果存在 1 ≤ i < n 1\leq i<n 1≤i<n,使得 i ⋅ ( i + 1 ) = n i\cdot(i+1)=n i⋅(i+1)=n,这样的话就会有重复。那我们应该怎么处理?是将 1 n \dfrac 1n n1再裂项一次?那序列 A A A的长度就大于 n n n了。是将 1 i ⋅ ( i + 1 ) \dfrac{1}{i\cdot(i+1)} i⋅(i+1)1和 1 n \dfrac 1n n1求和再裂项一次?这还是会有重复。
那该怎么办呢?我们可以先用 1 4 \dfrac 14 41来裂项。
1 4 = 1 4 − 1 5 + 1 5 − 1 6 + ⋯ − 1 n + 1 n = 1 20 + 1 30 + ⋯ + 1 ( n − 1 ) ⋅ n + 1 n \dfrac 14=\dfrac 14-\dfrac 15+\dfrac 15-\dfrac 16+\cdots-\dfrac 1n+\dfrac 1n=\dfrac{1}{20}+\dfrac{1}{30}+\cdots+\dfrac{1}{(n-1)\cdot n}+\dfrac 1n 41=41−51+51−61+⋯−n1+n1=201+301+⋯+(n−1)⋅n1+n1
已经有了 n − 3 n-3 n−3项,和为 1 4 \dfrac 14 41,还需要加上 3 4 \dfrac 34 43。
我们需要将 3 4 \dfrac 34 43分为若干个正整数的倒数的和, 3 4 = 1 2 + 1 4 = 1 3 + 1 4 + 1 6 \dfrac 34=\dfrac 12+\dfrac 14=\dfrac 13+\dfrac 14+\dfrac 16 43=21+41=31+41+61,那么
- 如果存在 1 ≤ i < n 1\leq i<n 1≤i<n,使得 i ⋅ ( i + 1 ) = n i\cdot(i+1)=n i⋅(i+1)=n,则将 1 n \dfrac 1n n1再裂项一次,并加上 1 2 + 1 4 \dfrac 12+\dfrac 14 21+41两项
- 如果不存在 1 ≤ i < n 1\leq i<n 1≤i<n,使得 i ⋅ ( i + 1 ) = n i\cdot(i+1)=n i⋅(i+1)=n,则加上 1 3 + 1 4 + 1 6 \dfrac 13+\dfrac 14+\dfrac 16 31+41+61三项
这样便保证了序列的长度为 n n n。
当 n ≤ 6 n\leq 6 n≤6时,用 i f if if判断 n n n的值并直接输出;当 n > 6 n>6 n>6时,用上面的方法来求解。这样能保证没有重复。当然,此时最大的 A i A_i Ai是远远小于 1 0 9 10^9 109的。
时间复杂度为 O ( ∑ n ) O(\sum n) O(∑n)。
code
#include<bits/stdc++.h>
using namespace std;
int t,n,fl,ans[100005];
int main()
{
scanf("%d",&t);
while(t--){
scanf("%d",&n);
if(n==1){
printf("Yes\n1\n");continue;
}
if(n==2){
printf("No\n");continue;
}
if(n==3){
printf("Yes\n2 3 6\n");continue;
}
if(n==4){
printf("Yes\n2 4 5 20\n");continue;
}
if(n==5){
printf("Yes\n3 4 5 6 20\n");continue;
}
if(n==6){
printf("Yes\n2 4 7 20 30 42\n");continue;
}
ans[0]=0;
fl=0;
for(int i=4;i<=n-1;i++){
ans[++ans[0]]=i*(i+1);
if(i*(i+1)==n) fl=1;
}
if(!fl){
ans[++ans[0]]=3;
ans[++ans[0]]=4;
ans[++ans[0]]=6;
ans[++ans[0]]=n;
}
else{
ans[++ans[0]]=2;
ans[++ans[0]]=4;
ans[++ans[0]]=n*(n+1);
ans[++ans[0]]=n+1;
}
printf("Yes\n");
for(int i=1;i<=n;i++){
printf("%d ",ans[i]);
}
printf("\n");
}
}