C. Maximal GCD

C. Maximal GCD
题意:输入 n k, 构造一个k个数的数列,k个数和为n,并使这k个数的最大公约数最大
****注释都在代码里了~

/* 首先是 范围 n,k都是1e10 ,
1.如果k 是按照1,2,3……的顺序 组成数列,那么根据等差数列求和得k*(k+1)/2,这个和要小于等于n得范围,计算得k要小于 141420
2.在就是 如果 如果组成的最小数的和 都大于 给定的n
以上两种情况   无法符合题意,输出 -1
else
 
 假如数A是所有数的 公约数,  那么A也是n的因子,
 n/A={b1,b2,b3...bk}  (表示需要构造的k个数)
 但前提是       {b1,b2,b3...bk}的和 >= (1,2,3……k)的和 
 因此 只需从大到小 枚举n的因子  得到不同的{b1,b2,b3...bk} ,直到 {b1,b2,b3...bk}>=(1,2,3……k)即可 开始构造数列 
 
 然后 只需  构造第1~k-1,并将每个数乘A,  最后一个数 通过作差 {b1,b2,b3...bk}-(1,2,3,……k-1) 并乘A即可 */ 
 
 
#include<bits/stdc++.h>
#define rep(i,j,n) for(ll i=j;i<=n;i++)
typedef long long ll;
const ll maxn=1e6+9;
using namespace std;
ll n,k,yz[maxn];//yz储存n的因子 
ll cnt;
void num(ll n) {   //计算并储存n的因子 , 用yz[]储存 
	ll i;
	for(i=1,cnt=1; i*i<=n; i++) {
		if(n%i==0) {
			if(n%i==i) {
				yz[++cnt]=i;
			} else {
				yz[++cnt]=i;
				yz[++cnt]=n/i;
			}
		}
	}
}
int main() {
	cin>>n>>k;//创建一个k个数字的严格递增的数列,并 保证和为n

	ll s=k*(k+1)/2;//表示k个数能构成的最小的和 
	if(k>141420||n<(s))  // 最小和超出了1e10范围 或者 超出了n 
		cout<<"-1";

	else {
		num(n);
		sort(yz+1,yz+1+cnt);    //对因子排序 

		ll flag=0,ksum;
		for(ll i=cnt; i>0; i--) {   //从大到小 枚举因子  
			ksum=n/yz[i];// k个数的总和 
			if(ksum-s>=0) {
				flag=1;
				ll sum=0;
				for(ll j=1; j<k; j++) {
					cout<<j*yz[i]<<" ";// 1,2,3……  将每个数乘n的因子yz[i]  
					sum+=j;
				}
				cout<<yz[i]*(ksum-sum);
				break;
			}
		}
		if(flag==0)
			cout<<"-1";
	}
	return 0;
}
 

参考的博主,传送门

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值