ARC163C Harmonic Mean

该问题是一个编程竞赛题目,要求找到一个长度为n的序列A,其元素互不相同且满足序列元素倒数之和等于1。利用数学裂项求和方法,可以发现序列可以由1/(i(i+1))的和构成,但要避免i(i+1)=n的情况导致重复。通过预处理特殊情况并处理可能的重复,可以构造出满足条件的序列A。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ARC163C Harmonic Mean

题目大意

给你一个正整数 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=1nAi1=1
  • A i A_i Ai互不相同
  • 1 ≤ A i ≤ 1 0 9 1\leq A_i\leq 10^9 1Ai109

如果有,就输出 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 1t500,1n500


题解

首先,我们知道 1 a − 1 a + 1 = 1 a ( a + 1 ) \dfrac{1}{a}-\dfrac{1}{a+1}=\dfrac{1}{a(a+1)} a1a+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=121+2131+n1+n1=21+61++(n1)n1+n1

因为 1 ≤ n ≤ 500 1\leq n\leq 500 1n500,所以 1 ≤ n ( n − 1 ) ≤ 250000 1\leq n(n-1)\leq 250000 1n(n1)250000,满足第三个条件,这样就可以得到一个 A A A序列。

但如果存在 1 ≤ i < n 1\leq i<n 1i<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=4151+5161+n1+n1=201+301++(n1)n1+n1

已经有了 n − 3 n-3 n3项,和为 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 1i<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 1i<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 n6时,用 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");
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值