Codeforces 999D Equalize the Remainders (set使用)

题目连接:Equalize the Remainders

题意:n个数字,对m取余有m种情况,使得每种情况的个数都为n/m个(保证n%m=0),最少需要操作多少次? 每次操作可以把某个数字+1。输出最少操作次数,和操作后的序列(可以输出任意一种)。

题解:用一个set来维护所有余数x(当前余数为x的数个数没凑够n/m个),对于每个数假设这个数的余数为t,当余数为t的数个数没凑够n/m时那这个数就不需要改变,如果已经凑够了,那就在set中找到第一个大于等于t的数(注意这里t可能比set中最大数的还要大,遇到这种情况就要将t变成set中最小数,举个例子m=5,余数为4和为0的数字凑够了,此时又来一个余数为4的数,该数应该变为余数为1)维护答案和序列,ans += (x-t+m)%m,out[i] += (x-t+m)%m。


 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef pair<int,int> P;
 4 typedef long long LL;
 5 const int MAX_N =2e5+9;
 6 int N,M,T,S;
 7 LL vec[MAX_N];
 8 LL res[MAX_N]; // 当前模的个数
 9 set<int> s;
10 LL out[MAX_N];
11 int main()
12 {
13     while(cin>>N>>M){
14         memset(res,0,sizeof(res));
15         memset(out,0,sizeof(out));
16         s.clear();
17         for(int i=0;i<M;i++){
18             s.insert(i);
19         }
20         for(int i=0;i<N;i++){
21             scanf("%lld",&vec[i]);
22         }
23         LL ans =0 ;
24         for(int i=0;i<N;i++){
25             LL t = vec[i]%M;
26             LL x ;
27             if(t > *s.rbegin()) x = *s.begin();
28             else x = *s.lower_bound(t);
29             res[x] ++;
30             if(res[x] == N/M) s.erase(x);
31             ans += (x - t + M)%M;
32             out[i] = (x - t + M)%M;
33         }
34         cout<<ans<<endl;
35         for(int i=0;i<N;i++){
36             printf("%lld ",vec[i] + out[i]);
37         }
38         cout<<endl;
39     }
40     return 0;
41 }

 

posted @ 2018-08-23 17:05  会打架的程序员不是好客服  阅读(425)  评论(0编辑  收藏  举报