Codeforces 999D Equalize the Remainders 【模拟】

考场的时候想到的n*m做法tle了,正解是O(n+m)

首先想到一个性质是不管a[i],a[j]相差多少,只要a[i],a[j]同余,那想让他们increase后%m得到另一个余数,那他们需要increse的次数是相等的。

所以我们想到把n个数按%m从0到m-1分成m类。这样就能贪心了,因为如果%m为0这样的数大于n/m个,那这样说明这里面的v.size()-n/m个数至少要加1,我们把这些多出来的%m为0的数转化成%m为1的数;如果小于n/m先不处理。一遍扫完我们发现m-1这一项会有很多数(因为前面的都压过来了)。

然后我们再扫一遍把多余的余m-1的数转移到之前不满n/m的就可以了。但这样复杂度是O(n*m),因为可能一开始余0里面有n个数,这样的话每个数都要不断的+1放到下一个余数里,再+1放到下一个余数里以此类推。

正解是把多出来的那些数放到一个叫fre的vector里(free是关键字所以不能用)【与此相对的是我把它放到下一个余数的vector中】,这样就巧妙地避免了我之前遇到的问题(不会重复加和删除)。这里说一下vector里方法的复杂度:push_back()和pop_back()是O(1);insert和erase是O(n)【我以前以为都是常数。。】

 

 1 #include
 2 #include
 3 #include
 4 using namespace std;
 5 
 6 vector<int> remain[200005];
 7 vector< pair<int,int> > fre; //first是index,second是余数 
 8 long long a[200005],pl[200005],ans;
 9 
10 int main(){    
11     int n,m; cin>>n>>m;
12     for(int i=1;i<=n;i++){
13         cin>>a[i];
14         remain[ a[i]%m ].push_back(i);
15     }
16      
17     for(int i=0;i//遍历每一个remainder
18         if( remain[i].size()>n/m ){
19             int tran = remain[i].size()-n/m;
20             while(tran--){
21                 fre.push_back( make_pair(remain[i].back(),i) );
22                 remain[i].pop_back();
23             }
24         }
25         else if( remain[i].size()m ){
26             int need = n/m - remain[i].size();
27             //free里面的余数肯定比现在的小
28             while( (!fre.empty() ) && need-- ){
29                 pl[ fre.back().first ]+= i - fre.back().second;
30                 ans+=i - fre.back().second;
31                 remain[i].push_back( fre.back().first  );
32                 fre.pop_back();
33             } 
34         }
35     }
36     
37     for(int i=0;i){
38         if( remain[i].size()m){
39             int need=n/m-remain[i].size();
40             //free里面的余数肯定比现在的大 
41             while( need-- ){
42                 pl[ fre.back().first ]+= (m-fre.back().second) + i;
43                 ans+=(m-fre.back().second) + i;
44                 remain[i].push_back( fre.back().first  );
45                 fre.pop_back();
46             }     
47         }
48     }
49     
50     cout<endl;
51     for(int i=1;i<=n;i++) cout<" ";
52     
53     return 0;
54 }

 

转载于:https://www.cnblogs.com/ZhenghangHu/p/9220951.html

你可能感兴趣的:(Codeforces 999D Equalize the Remainders 【模拟】)