zoukankan      html  css  js  c++  java
  • 题解 | CF1328F. Make k Equal (思维,前缀 & 后缀和)

    题目链接:Here

    题意:把 (n) 个数变成 (k) 个相同的数,每次可以把 (n) 个数里最大的 (-1) 或最小的 (+1) ,问最小改变次数

    思路:

    我们可以枚举,把 (n) 个数变成 (k)(a[i]) (这个相同的数一定是数组里的数,因为如果不是,那么改变次数一定会比正常多)

    如果相同的数大于 (k) 个,那么改变次数为 (0) ,特判掉

    有三种情况,一种是只动前面,一种只动后面,还有就是前后都动

    因为是改变最大或最小的数,所以我们只有把所有小于 (a[i]) 的数变成 (a[i]-1) (或者大于 (a[i]) 的数变成(a[i]+1) )才能进行下一次的改变

    然后接着考虑,在什么情况下可以动前面呢,当然是他前面的数大于((k-1))个,同理,在他后面的数大于 ((k-1)) 个时才可以动后面,然后在任何情况下都可以前后都动( 在$(i=1) $时就相当于是动后面结果不冲突)

    以只动前面为例

    (tem1 = (sumlimits_{j=1}^i((a[i] - 1) -a[j]) + k)

    化简一下发现

    (tem1 = sumlimits_{j=1}^i(a[i] - 1) -sumlimits_{j=1}^ia[j] + k)

    就是 (i*(a[i]-1)-a[i]) 的前缀和 (+k) ,提前搞一个前缀和可以降低时间复杂度

    只动后面同理

    (tmp2 = sumlimits_{j=i}^na[i] -sumlimits_{j=i}^n(a[j] + 1) + k)

    动两边,这时相等的数的个数恰好为 (n) ,把他们都搞成 (a[i]) 然后再减掉多余的

    (tmp3 = sumlimits_{j=i}^na[j] - sumlimits_{j=1}^ia[j] + sumlimits_{j=1}^ia[i] - sumlimits_{j=i}^na[i] - (n - k))

    记录好前缀和 和(后缀和?)就可以用 (mathcal{O}(n))​ 的复杂度解决掉这个问题了

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    const ll inf = 1e17;
    ll a[200009];
    ll cnt[200009];
    ll sumq[200009], sumh[200009];
    int main() {
        int n, k;
        ll ans = inf;
        scanf("%d%d", &n, &k);
        for (int i = 1; i <= n; i++) {
            scanf("%lld", &a[i]);
        }
        sort(a + 1, a + 1 + n);
        for (int i = 1; i <= n; i++) sumq[i] = sumq[i - 1] + a[i];
        for (int i = n; i >= 1; i--) sumh[i] = sumh[i + 1] + a[i];
        for (int i = 1; i <= n; i++) {
            if (a[i] == a[i - 1])cnt[i] = cnt[i - 1] + 1;
            else cnt[i] = 1;
            if (cnt[i] >= k) {
                puts("0");
                return 0;
            }
        }
        for (int i = 1; i <= n; i++) {
            if (i >= k) {
                ll tem1 = i * (a[i] - 1) - sumq[i] + k;
                ans = min(tem1, ans);
            }
            if (n - i + 1 >= k) {
                ll tem2 = n - i + 1;
                tem2 = sumh[i] - tem2 * (a[i] + 1) + k;
                ans = min(tem2, ans);
            }
            if (i < k && (n - i + 1) < k) {
                ll tem3 = i * a[i] - sumq[i] + sumh[i] - (n - i + 1) * a[i] - (n - k);
                ans = min(tem3, ans);
            }
        }
        printf("%lld
    ", ans);
        return 0;
    }
    

    便捷写法

    int main() {
        cin.tie(nullptr)->sync_with_stdio(false);
        int n, k;
        cin >> n >> k;
        vector<ll> a(n);
        for (ll &x : a) cin >> x;
        sort(a.begin(), a.end());
        for (int i = 0; i + k - 1 < n; ++i) {
            if (a[i] == a[i + k - 1])
                return printf("0
    "), 0;
        }
    
        ll lcost = 0;
        ll rcost = 0;
        for (int i = 0; i < k; ++i) {
            lcost += a[k - 1] - a[i];
            rcost += a[n - 1 - i] - a[n - k];
        }
        for (int j = k; j < n; ++j) {
            if (a[k - 1] == a[j]) lcost--;
            if (a[n - k] == a[n - 1 - j]) rcost--;
        }
        ll sum = 0;
        for (int i = 0; i < n - 1 - i; ++i) sum += a[n - 1 - i] - a[i];
        ll ans = min(sum - (n - k), min(lcost, rcost));
        cout << ans;
    }
    

    The desire of his soul is the prophecy of his fate
    你灵魂的欲望,是你命运的先知。

  • 相关阅读:
    UVA 1386 Cellular Automaton
    ZOJ 3331 Process the Tasks
    CodeForces 650B Image Preview
    CodeForces 650A Watchmen
    CodeForces 651B Beautiful Paintings
    CodeForces 651A Joysticks
    HUST 1601 Shepherd
    HUST 1602 Substring
    HUST 1600 Lucky Numbers
    POJ 3991 Seinfeld
  • 原文地址:https://www.cnblogs.com/RioTian/p/15157519.html
Copyright © 2011-2022 走看看