【CodeForces 803 C】Maximal GCD(GCD+思维)

You are given positive integer number n. You should create such strictly increasingsequence of k positive numbers a1, a2, ..., ak, that their sum is equal to n and greatest common divisor is maximal.

Greatest common divisor of sequence is maximum of such numbers that every element of sequence is divisible by them.

If there is no possible sequence then output -1.

Input

The first line consists of two numbers n and k (1 ≤ n, k ≤ 1010).

Output

If the answer exists then output k numbers — resulting sequence. Otherwise output -1. If there are multiple answers, print any of them.

Examples

Input
6 3
Output
1 2 3
Input
8 2
Output
2 6
Input
5 3
Output
-1
题意:

给出正整数n。我们要创建k个正数1,  2,...,  k的严格增加序列,它们的和等于n,并使其最大公约数是最大的。

序列的最大公约数是:序列的每个元素都可以被它们整除。

如果没有可能的序列,则输出-1。

思路:

(1) 若k个数字的gcd为A,那么n一定可以整除A,所以考虑从n的因子里选出这个A来,先求出k个数字可以表示的最小的数,即 1+2+3+...+k = k(k+1)/2

(2) 设a1 a2 ... ak为解,那么a1+a2+...+ak=n,设gcd(a1,a2...,ak)=A,那么 a1=A*b1 ,a2=A*b2 … ak=A*bk。

(3) 那么gcd(b1,b2,...,bk)=1,且A*(b1+b2+...+bk)=n,所以n%A=0,说明A为n的因数。

 

ps:n/A = b1+b2+...+bk

(1) 首先因为n≤1010,所以通过 k(k+1)/2 可知:k最大为141420。

(2) 然后处理出所有n的因数,因数从大往小找,找到第一个符合 n/A≥k(k+1)/2 的因数即可。反正b1,b2,…,bk它们的gcd是1,直接令前k-1个数分别是1~k-1,第k项为 (n/A-前k项的总和)

(3) 将最后的答案全部乘A即可!

#include<bits/stdc++.h> 
using namespace std;
typedef long long ll;
ll A[10005],cnt;
//A[]储存n的因子  cnt为因子个数 
void fact(ll n)
{
    ll i;
    for(i=1,cnt=1;i*i<=n;i++)
    {
        if(n%i==0)
        {
            if(n%i!=i)
            {
                A[++cnt]=i;
                A[++cnt]=n/i;
            }
            else A[++cnt]=i;
        }
    }
}
int main()
{
    //k最大为141420 
    ll n,k,i,j;
    while(scanf("%lld%lld",&n,&k)!=EOF)
    {
        ll fk=k*(k+1)/2;     //k个数所能组成的最小值 
        if(k>141420)
            printf("-1\n");
        else if(n<fk)
             printf("-1\n");
        else
        {
            fact(n);
            sort(A+1,A+cnt+1);
            ll ksum;
            int flag=0;
            for(i=cnt;i>0;i--)
            {
                ksum=n/A[i];  //k个数的总和  
                if(ksum-fk>=0)
                {
                    flag=1;
                    ll sum=0; //前k-1个数的总和 
                    for(j=1;j<k;j++)
                    {
                        printf("%lld ",j*A[i]);
                        sum+=j;
                    }
                    printf("%lld\n",A[i]*(ksum-sum));
                    break;
                }
            }
            if(!flag)printf("-1\n");
        }
    } 
    return 0;
}

 

转载于:https://www.cnblogs.com/kannyi/p/9610761.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值