题意: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 }