原题地址:http://codeforces.com/contest/999/problem/D
题意:本题就是给你n,m,保证n能被m整除,给你n个数,对这些数操作+=1,使得这些数%m后,得到的数是从0~m-1,且没个数出现n/m次。
思路:贪心,首先记录每个取余m后的结果数的个数,如果个数不大于n/m则不用改变,否则(需要改变)插入set,然后二分查找出大于该数的且余数个数小于n/m的数,把数组变化,同时更新对应值。注意如果找不到大于该数的且余数个数小于n/m的数,就是小于它的第一个数。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 3e5 + 5;
ll a[maxn];
ll dir[maxn];
ll n, m;
int main() {
scanf("%I64d%I64d", &n, &m);
ll num = n / m;
for(ll i = 1; i <= n; i++) {
scanf("%I64d", &a[i]);
dir[a[i] % m]++;
}
set<ll>s;
for(ll i = 0; i < m; i++) {
if(dir[i] < num) s.insert(i);
}
ll ans = 0;
for(ll i = 1; i <= n; i++) {
if(s.size() == 0) break;
if(dir[a[i] % m] <= num) continue;
dir[a[i] % m]--;
set<ll>::iterator it;
it = s.lower_bound(a[i] % m);
//it=lower_bound(s.begin(),s.end(),a[i]%m);
//这里特别奇怪,如果用下面这种写法的话,就会T
if(it != s.end()) {
dir[*it]++;
ans += *it - a[i] % m;
a[i] += *it - a[i] % m;
if(dir[*it] == num) s.erase(*it);
} else {
dir[*s.begin()]++;
ll k = m - a[i] % m;
k += *s.begin();
ans += k;
a[i] +=k;
if(dir[*s.begin()] == num) s.erase(*s.begin());
}
}
printf("%I64d\n", ans);
for(int i = 1; i <= n; i++) printf("%I64d ", a[i]);
return 0;
}