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;
}

全部评论
这样思路比较好想,我是直接打表的
点赞 回复 分享
发布于 01-26 21:33 浙江
这里g说的比出题人清楚感谢
点赞 回复 分享
发布于 01-27 21:39 广东

相关推荐

评论
1
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务