CF999D 余数平衡

向在大年三十还在看算法的你们致敬!大家春节快乐!

1 CF999D 余数平衡

2 题目描述

时间限制 \(3s\) | 空间限制 \(256M\)

给出一个数组包含从 \(a_1,𝑎_2,…,𝑎_𝑛\)\(n\) 个整数和一个正整数 \(m\)\(𝑚\)\(a\) 的除数。单次修改时,可以在 \(1\)\(n\) 之间选择任意位置并将 \(a_i\) 增加1。
\(𝑐_𝑟(0≤𝑟≤𝑚-1)\) 代表当除以 \(m\) 时具有余数 \(𝑟\) 的个数。

请以尽量少的操作次数使得 \(𝑐_0=𝑐_1=⋯=\)\(𝑐\)\(_m\)\(_-\)\(_1\)\(=\frac{𝑛}{𝑚}\)。找到满足上述要求的最少操作次数。

3 题解

这是一道明显的贪心。首先我们可以考虑将所有数模上 \(m\) 的余数存储起来,由于我们要找的是某固定余数的数量,我们可以换一种存法:对于每种可能的余数用一个队列维护余数为该数的数的坐标。存储起来后,我们一次遍历所有可能的余数。如果当前余数的个数大于 \(\frac{n}{m}\),那么这个余数中的一些数肯定可以用于给个数少的余数增加个数,因此我们将这些数推入另一个专门存放这些多余的数的队列。如果我们发现一个数量小于 \(\frac{n}{m}\),那么我们取队头的那个元素并计算其变为当前余数的代价。如果两个数中我们要使余数较小的那个数 \(s\) 的余数增加到余数较大的那个数 \(t\) 的余数,那么我们需要增加的就是 \(t \% m - s \%m\)。如果我们要使余数较大的数 \(t\) 增加到余数较小的数 \(s\),那么我们需要增加的就是 \(s \%m + m - t \% m\)

此时可能出现一种问题:开始的几个小余数数量全部没有 \(\frac{n}{m}\) 大,导致我们开始无法补偿,后面溢出。为了解决这一问题,我们可以破环为链,将整个循环遍历两遍,从 \(0\) 遍历到 \(2*n - 1\)。这样我们在第二遍遍历到的时候就可以用后面的余数弥补了。

4 代码(空格警告):

#include <iostream>
#include <queue>
using namespace std;
const int N = 2e5+10;
#define int long long
int n, m, c, cnt;
int a[N];
queue<int> q[N];
queue<int> Q;
signed main()
{
    cin >> n >> m;
    for (int i = 1; i <= n; i++) cin >> a[i];
    c = n / m;
    for (int i = 1; i <= n; i++) q[a[i] % m].push(i);
    for (int i = 0; i < 2 * m; i++)
    {
        while (q[i%m].size() > c)
        {
            Q.push(q[i%m].front());
            q[i%m].pop();
        }
        while (Q.size() && q[i%m].size() < c)
        {
            if (i % m < a[Q.front()] % m)
            {
                cnt += (i % m) + m - (a[Q.front()] % m);
                a[Q.front()] += (i % m) + m - (a[Q.front()] % m);
                q[i%m].push(Q.front());
                Q.pop();
            }
            else
            {
                cnt += (i % m - a[Q.front()] % m);
                a[Q.front()] += (i % m - a[Q.front()] % m);
                q[i%m].push(Q.front());
                Q.pop();
            }
        }
    }
    cout << cnt << endl;
    for (int i = 1; i <= n; i++) cout << a[i] << " ";
    return 0;
}

欢迎关注我的微信公众号:智子笔记

posted @ 2021-02-11 12:00  David24  阅读(125)  评论(0编辑  收藏  举报