[CodeForces 999D] Equalize the Remainders

You are given an array consisting of n n n integers a a a1, a a a2,…, a a an, and a positive integer m m m. It is guaranteed that m m m is a divisor of n n n.In a single move, you can choose any position i i i between 11 and n n n and increase a a ai by 1 1 1.Let’s calculate C C Cr ( 0 ≤ r ≤ m − 1 ) (0≤r≤m−1) (0rm1) — the number of elements having remainder r r r when divided by m m m. In other words, for each remainder, let’s find the number of corresponding elements in a a a with that remainder.Your task is to change the array in such a way that C C C0= C C C1=⋯= C C Cm-1= n / m n/m n/m.Find the minimum number of moves to satisfy the above requirement.
Input
The first line of input contains two integers n n n and m m m
( 1 ≤ n ≤ 2 ⋅ 105 , 1 ≤ m ≤ n 1 ≤ n ≤ 2 ⋅ 105 , 1 ≤ m ≤ n ) (1≤n≤2⋅105,1≤m≤n1≤n≤2⋅105,1≤m≤n) (1n2105,1mn1n2105,1mn). It is guaranteed that m m m is a divisor of n n n.The second line of input contains n n n integers a a a1, a a a2,…, a a an (0≤ a a ai≤109), the elements of the array.OutputIn the first line, print a single integer — the minimum number of moves required to satisfy the following condition: for each remainder from 0 0 0 to m − 1 m−1 m1, the number of elements of the array having this remainder equals n / m n/m n/m.In the second line, print any array satisfying the condition and can be obtained from the given array with the minimum number of moves. The values of the elements of the resulting array must not exceed 1018.
Output
In the first line, print a single integer — the minimum number of moves required to satisfy the following condition: for each remainder from 0 0 0 to m − 1 m−1 m1, the number of elements of the array having this remainder equals n / m n/m n/m.In the second line, print any array satisfying the condition and can be obtained from the given array with the minimum number of moves. The values of the elements of the resulting array must not exceed 1018.

题意
给一个n及一个m,保证m为n的因子,接下来给n个数 C C C1 ~ C C Cn。在有限步操作后使这n个数中模 m m m 0 0 0~ m − 1 m-1 m1的数个数均为 n / m n/m n/m个。每步操作可以任选一个数+1。问最少多少步操作可实现这个目标。输出这个最少步数及修改后的数列。
sample input

6 3 
3 2 0 6 10 12 

sample output

3
3 2 0 7 10 14 

sample input

4 2
0 1 2 3

sample output

0
0 1 2 3 

这题思路就是简单贪心,对于每个数 a a ai,判断在这之前是否已经有 n / m n/m n/m个数模 m m m的余数为 a a ai% m m m的数,如果有就把 a a ai+1直到之前没有 n / m n/m n/m个数模 m m m的余数为 a a ai% m m m为止,同时把操作步数计入 a n s ans ans,最后输出 a n s ans ans即可。
最开始用数组模拟指针的形式写了个程序, b [ i ] b[i] b[i]记录多余多少个余数为 i i i 的数, p [ i ] [ 0 ] p[i][0] p[i][0]指向 i i i之前最近的一个 p [ ] p[] p[]不为0的值, p [ i ] [ 1 ] p[i][1] p[i][1]指向 i i i之后最近的一个 p [ ] p[] p[]不为0的值,然而TLE了。。。

#include<stdio.h>
long long a[200010],b[200010];
long long n,m;
long long target,temp,s,z;
long long ans;
long long p[200010][2];//¨ºy¡Á¨¦?¡ê?a???? 
long long abs(long long a)
{
 if (a<0) return -a;else return a;
}
void change(long long i)
{
 p[p[i][0]][1]=p[i][1];
 p[p[i][1]][0]=p[i][0];
 return;
}
int main()
{
 while(scanf("%lld%lld",&n,&m)!=EOF)
 {
  ans=0;
  target=n/m;
  for(long long i=0;i<n;i++)
  {
   scanf("%lld",&a[i]);
   b[a[i]%m]++;
  }
  for(long long i=0;i<m;i++)p[i][1]=(i+1)%m,p[i][0]=(i+m-1)%m;
  for(long long i=0;i<m;i++) {b[i]-=target;if(!b[i])change(i);}
  for(long long i=0;i<n;i++)
  {
   temp=a[i]%m;
   if(b[temp]>0)
   {
    s=p[temp][1];
    while(b[s]>=0)s=p[s][1];  
    ans+=(s+m-temp)%m;
    a[i]+=(s+m-temp)%m;
    b[temp]--;
    b[s]++;
    if(!b[temp]) change(temp);
    if(!b[s]) change(s);
   }
  }
  printf("%lld\n",ans);
  for(long long i=0;i<n;i++) printf("%lld ",a[i]);
  printf("\n");
 }
 return 0;
}

然后用STL map重写了一个,思路没有变

#include<stdio.h>
#include<map>
using namespace std;
long long a[200010],b[200010];
long long n,m;
long long target,temp,s;
long long ans;
map<long long,int>z;
int main()
{
 scanf("%lld%lld",&n,&m);
 ans=0;
 target=n/m;
 for(long long i=0;i<n;i++)
 {
  scanf("%lld",&a[i]);
 }
 for(long long i=0;i<m;i++)z[i]=target;
 for(long long i=0;i<n;i++)
 {
  long long c;
  temp=a[i]%m;
  if(temp>(*z.rbegin()).first) {c=(*z.begin()).first;(*z.begin()).second--;if(!(*z.begin()).second) z.erase((*z.begin()).first);}
  else {c=(*z.lower_bound(temp)).first;(*z.lower_bound(temp)).second--;if(!(*z.lower_bound(temp)).second) z.erase((*z.lower_bound(temp)).first);}
  ans=ans+(c+m-temp)%m;
  a[i]=a[i]+(c+m-temp)%m;
 }
 printf("%lld\n",ans);
 for(long long i=0;i<n;i++) printf("%lld ",a[i]);
 printf("\n");
 return 0;
}

你可能感兴趣的:(技巧-STL使用,思想-贪心)