https://www.luogu.com.cn/problem/CF803C
-问题描述
请你构造一个长度为 k 的严格上升正整数序列,使得所有数的和恰好为 n,并且所有数的最大公约数最大。输出这个序列。如果没有合法的序列输出 −1。如果有多个合法的序列,可以输出任意一个。
1≤n,k≤1e10
- 解题思路
题目讲了,这是一个严格递增的正整数序列,那么要使得值最小的情况就是 1,2,3,4...... 而它的总和是 (n×(n+1))/2,题目要我们把能找到这个序列的最大公约数和序列最小情况的总和作比较,若该最小总和更大,则一定不可能构造出一个符合条件的序列,否则则一定可以构造出一组满足条件的序列。
- 算法描述
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
ll n, k;
// 检查是否可以构造一个和为 n 的 k 个数的序列
bool check(ll n)
{
return k + 1 <= n * 2 / k;
}
int main() {
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin >> n >> k;
if (!check(n)) {
cout << -1<<'\n';
return 0;
}
ll ans = 0; // 初始化 ans 为 0,用于存储最大公约数的候选值
// 遍历从 1 到 sqrt(n) 的所有整数 i
for (ll i = 1; i * i <= n; ++i) {
// 如果 i 是 n 的因数,并且可以构造一个和为 n/i 的 k 个数的序列
if (n % i == 0 && check(n / i)) {
// 更新 ans 为 i 和当前 ans 的较大值
ans = max(ans, i);
}
// 如果 i 是 n 的因数,并且可以构造一个和为 i 的 k 个数的序列
if (n % i == 0 && check(i)) {
// 更新 ans 为 n/i 和当前 ans 的较大值
ans = max(ans, n / i);
}
}
// 输出 k-1 个数,每个数都是 ans 的倍数,且递增
for (int i = 1; i <= k - 1; i++) {
cout << ans * i << " ";
// 从 n 中减去已经输出的数的和
n -= ans * i;
}
// 输出最后一个数,使得这 k 个数的和为 n
cout << n << '\n';
return 0;
}
- 力扣提交结果
- 分析、讨论与总结
从1开始·一直枚举到k−1,用 n 累减每一个数,最后将剩下值输出。这种枚举方式是一定不会有重复的,但要注意每一个数在输出时都要乘以之前求出的最大公因数。同时,本题还需要注意看题目的数据范围,我们知道是要开long long的。