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;
}