題意: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 }
本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。