CodeForces 803C

Maximal GCD

Describtion:

You are given positive integer number n. You should create such strictly increasing sequence 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个严格单调递增的数之和。其中求出k个数的最大公约数最大的情况,有多个的话给出任意一个就可以。

解题思路:
1.既然是要求k个数的最大公约数最大,那么就从最大公约数入手,假设最大公约数是g
2.由于g是每个数的因子,因此可以有:   n = b1*g + b2*g + b3*g + … … + bk*g , 显然这个g也是n的因子
3.根据上式,也就有 n = g*(b1+b2+b3+ …+ bk)。bi也是严格递增的,最多有k个,那么对于g来说是有有下限的,也就是 n/g < (1+k)*k/2
4.枚举数n的全部因子,只要去找前  n 个数即可。不过这样计算的时候,每次需要考虑两个,并取两个因子中更大的可行解。
5.对于同一个g来说,任意的满足的b1,b2,b3,….,bk序列一定可以等价为一个1,2,3,…,i,i+1,..,k-1,bk+x序列(比如 26=2*(1+3+4+5) 等价于 26=2*(1+2+3+7))因为只要将前面少掉的因子全都加到最后一项上,肯定是满足严格单调递增的。
6.由于n也是小于 1010 ,下面如果 k>2311=(2.14109 )那么k*(k+1)/2是肯定超过n了,根据3可知这是不可能的。以此来防止超过long long的表示范围。( 2631=9.231018 ,而k最大也可以取到 1010 ,那么need的计算会超过表示范围)

源代码:

#include<stdio.h>
#include<math.h> 

long long MAX = (1<<31)-1;

int main(){
    long long n,k;
    scanf("%lld %lld",&n,&k);
    long long need = k * (k + 1) / 2;
    if(n < need || k > MAX)                //防止超过long long的表示范围
        puts("-1");
    else{
        long long g = 1;
        long long i = sqrt(n);
        for(i; i >=1 ; i--){
            if(n % i == 0){
                long long now = n / i;
                if(now >= need)            //now是个数和,i是因子 
                    g = g>i?g:i;
                if(i >= need)              //考虑i是个数和,need是因子的情况 
                    g = g>now?g:now;
             }

        }
        long long now = n / g;
        for(long long i = 1; i < k; i++){
           printf("%lld ",i * g);
           now -= i;
        } 
        printf("%lld\n",g * now);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值