G题 (打表+二分)
#include <bits/stdc++.h> using i64 = long long; void Solve() { for (int i = 1; i <= 1000; i ++ ) { std::cout << i << ' ' << 1000 % i << '\n'; } } int main() { std::ios::sync_with_stdio(false); std::cin.tie(nullptr); int tt; std::cin >> tt; while (tt --) Solve(); return 0; }
思路:
可以发现对于每一个 d ,从 x//(d+1)+1 开始,后面形成的是以 d 为公差的递减等差数列。
那么对于小规模数据 (1e6) ,我们直接 sort 解决。
对于大的,我们可以开一个大小为 1001 的数组,存下每个 d 的首相,之前的可以用 1e6 数组中预处理好的。
最后我们二分,取每个大于等于 mid 的数,以取出来的数量是否大于等于 k 为依据,即可算出答案。
代码:
#include <bits/stdc++.h> using i64 = long long; constexpr int N = 1E6; int main() { std::ios::sync_with_stdio(false); std::cin.tie(nullptr); int n, k; std::cin >> n >> k; int M = std::min(n, N); std::vector<int> a(M + 1, n); for (int i = 1; i <= M; i ++ ) { a[i] %= i; } std::sort(a.begin() + 1, a.end()); if (n <= N) { i64 ans = 0; for (int i = n; i >= n - k + 1; i -- ) { ans += a[i]; } std::cout << ans << '\n'; }else { std::vector<int> d(1001); for (int i = 1; i < 1001; i ++ ) { int st = n / (i + 1) + 1, mod = n % st; d[i] = mod; if (st <= M) { d[i] = std::max(0LL, - i64(M - st + 1) * i + d[i]); } } auto check = [&](int x) { int bd = std::lower_bound(a.begin() + 1, a.end(), x) - a.begin(); i64 res = M + 1 - bd; for (int i = 1; i < 1001; i ++ ) { if (d[i] >= x) { res += (d[i] - x) / i + 1; } } return res; }; int l = 0, r = n + 1; while (l + 1 != r) { int mid = l + r >> 1; if (check(mid) >= k) l = mid; else r = mid; } i64 ans = 0; int bd = std::lower_bound(a.begin() + 1, a.end(), l) - a.begin(); for (int i = bd; i <= M; i ++ ) { ans += a[i]; } for (int i = 1; i < 1001; i ++ ) { if (d[i] >= l) { int num = (d[i] - l) / i + 1; ans += (-i64(num - 1) * i + d[i] + d[i]) * num / 2; } } int now = check(l); ans -= i64(now - k) * l; std::cout << ans << '\n'; } return 0; }