题目大意
给出一个整数
n
n
n,让你把
n
n
n拆成由
k
k
k个整数组成的,严格递增的的序列。
问这个数列最大公约数是多少,并输出相应的数列。
时间限制
1s
数据范围
n , k ≤ 1 0 10 n,k\le10^{10} n,k≤1010
题解
不妨设这个数列的公因数为
g
g
g,但不一定是最大的。
先来看一下它有什么性质。
不妨设数列为
a
1
,
a
2
,
⋯
,
a
k
a_1,a_2,\cdots,a_k
a1,a2,⋯,ak,
∑
i
=
0
k
a
i
=
n
\displaystyle\sum_{i=0}^k a_i = n
i=0∑kai=n
因为
g
g
g是每一个
a
i
a_i
ai的因数,所以
g
g
g也一定是
n
n
n的因数。
因此现在
g
g
g能取的范围就明显小了很多,只需要
O
(
n
)
O(\sqrt n)
O(n)的复杂度就可以枚举出所有可能的
g
g
g。
现在就要考虑如何判断一个
g
g
g是否合法。
因为和是一定的,考虑构造一个和最小的合法数列。
显然这个数列就是
g
,
2
×
g
,
⋯
,
k
×
g
g,2\times g,\cdots,k\times g
g,2×g,⋯,k×g
这个数列的和是非常容易求出来的,套用一定等差数列求和公式即可。
一般来说,
n
n
n都不是巧合能凑出这个和的情况,如果
n
n
n比这个和要小,显然是不可以的。如果
n
n
n比较大,则需要考虑一种构造方式。
最简单的一个想法,就是把差值全部加到最后一个数上,这样就只需要改变一个数。
但是还有一个条件,就是公因数要为
g
g
g,那么显然这个差值就必须是
g
g
g的倍数。
由于输出的数比较多,要使用输出优化。
Code
//#pragma GCC optimize (2)
//#pragma G++ optimize (2)
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iostream>
#include <queue>
#define ll long long
#define G getchar
using namespace std;
ll read()
{
char ch;
for(ch = G();ch < '0' || ch > '9';ch = G());
ll n = 0;
for(;'0' <= ch && ch <= '9';ch = G())n = (n<<1)+(n<<3)+ch-48;
return n;
}
void write(ll x)
{
if (x > 9)
{
write(x / 10);
putchar(x % 10 + 48);
}
else putchar(x + 48);
}
const int N = 200005;
ll n , k , tmp , mi , ans;
bool pd(ll tmp)
{
mi = n - k * (k + 1) / 2 * tmp;
if ((n - mi) % tmp == 0) return 1; else return 0;
}
int main()
{
//freopen("i.in","r",stdin);
//freopen("e.out","w",stdout);
n = read();
k = read();
tmp = 2 * n / k / (k + 1);
if (tmp == 0)
{
puts("-1");
return 0;
}
for (ll i = 1 ; i * i <= n && i <= tmp; i++)
if (n % i == 0)
{
if (n / i <= tmp)
{
if (pd(n / i))
{
ans = n / i;
break;
}
}
if (pd(i)) ans = i;
}
mi = n - k * (k + 1) / 2 * ans;
for (ll i = 1 ; i < k; i++)
{
write(i * ans);
putchar(' ');
}
write(ans * k + mi);
return 0;
}