题意:对于给定n,k 求一个有k个数的上升序列,序列的和为n。且序列的最大公约数最大。
首先1s的时间 n k的数量级都是1e10 ,因此肯定要降低复杂度。
假设存在一个这样的序列,设序列的最大公约数为gcd,那么这个序列一定可以为
1∗gcd,2∗gcd,3∗gcd....(k−1)gcd,k∗gcd
这个序列和的最大值为gcd∗k∗(k+1)2
且这个序列满足
gcd∗k∗(k+1)2≤n
n最大取1e10,可以考虑gcd=1的情况,用(k+1)2代替k∗(k+1)此时k取得最大值2√∗105−1
所以,当k比最大值大的时候就无法满足条件,输出-1;
如果要构造一个存在最大的最大公约数的序列,可以利用n的因子进行构造,用数组存取n的因子,从大向小遍历。
当某个因子d能够满足d∗k∗(k+1)2≤n时,说明这个因子可以用来进行构造,前k-1个因子直接按1∗d,2∗d...(k−1)∗d构造即可,对于第k个数,因为k*d可能不能正好满足k个数相加等于n,因此用n-(前面k-1个数的和)构造。
证明一下第k个数可以这样构造:
因为前k-1个数的和为d∗k∗(k−1)2,
所以第k个数为n−d∗k∗(k−1)2。
因为d是n的因子,所以第k个数是一个整数。
对于第k个数除以d的结果nd−k∗(k−1)2,当第k个数恰好为k*d时,这个结果也是k。
注意的一点是在判断 因子是否满足条件d∗k∗(k+1)2≤n时,左边的结果可能会爆longlong。。可以强制转换成long double进行比较。。
#1include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N = 1E6;
ll gcd[N];
int main(){
ll n,k;
while(~scanf("%lld %lld",&n,&k)){
if(k>=1e5*1.414-1) puts("-1");
else{
int cnt=0;
for(int i=1;i<=sqrt(n);i++){
if(n%i==0){
gcd[cnt]=i;
cnt++;
gcd[cnt]=n/i;
cnt++;
}
}
sort(gcd,gcd+cnt);
ll sum=0;
int flag=1;
for(int i=cnt-1;i>=0;i--){
if((long double)gcd[i]*(long double)k*(long double)(k+1)/2<=(long double)n){
flag=0;
for(int j=1;j<k;j++){
printf("%lld ",j*gcd[i]);
sum+=j*gcd[i];
}
printf("%lld\n",n-sum);
break;
}
}
if(flag) puts("-1");
}
}
}