CodeForces - 999D Equalize the Remainders (模拟+set)
You are given an array consisting of nn integers a1,a2,…,ana1,a2,…,an , and a positive integer mm . It is guaranteed that mm is a divisor of nn .
In a single move, you can choose any position ii between 11 and nn and increase aiai by 11 .
Let's calculate crcr (0≤r≤m−1)0≤r≤m−1) — the number of elements having remainder rr when divided by mm . In other words, for each remainder, let's find the number of corresponding elements in aa with that remainder.
Your task is to change the array in such a way that c0=c1=⋯=cm−1=nmc0=c1=⋯=cm−1=nm .
Find the minimum number of moves to satisfy the above requirement.
Input
The first line of input contains two integers nn and mm (1≤n≤2⋅105,1≤m≤n1≤n≤2⋅105,1≤m≤n ). It is guaranteed that mm is a divisor of nn .
The second line of input contains nn integers a1,a2,…,ana1,a2,…,an (0≤ai≤1090≤ai≤109 ), the elements of the array.
Output
In the first line, print a single integer — the minimum number of moves required to satisfy the following condition: for each remainder from 00 to m−1m−1 , the number of elements of the array having this remainder equals nmnm .
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 10181018 .
Examples
6 3
3 2 0 6 10 12
3
3 2 0 7 10 14
4 2
0 1 2 3
0
0 1 2 3
分析:
题目意思
首先给出n,m
第二行给出n个数
要求这n个数分为m组,组内n/m个数,要求第一组数%m==0,第二组数%m==1
第m组数%m==m-1,对于不满足要求的数,每次可以加1,问你最少的操作次数和所有操作完成之和的n个数
拿样例来说吧
3 2 0 6 10 12
n==6,m==3
6个数,分为3组,每组两个
第一组%3==0
第二组%3==1
第三组%3==2
3和0一组,%3==0
7(6+1=7)和10一组 %3==1
2和14(12+2=14)一组 %3==2
最少操作次数3次
操作之后的数组:
3 2 0 7 10 14
做法:
利用set把可能的余数0到m-1存起来(都是%m嘛),这个叫做目标余数
然后从原数组第一个开始遍历
x=a[1]%m,x叫做原余数
找到和原余数最近的没有用过的目标余数(在set里面找)
原余数可能会大于目标余数(目标余数只能出现n/m次,因为一组只能由n/m个数,达到n/m次数的目标余数就会删除)
那么这时候目标余数就是取set里面第一个
取第一个的原因:对数组里面的数只能执行加的操作,比如现在原余数是2,但是set里面最大的目标余数都只有1(目标余数2出现了n/m次,被删了),因为只有加的操作,由要使得
原余数2变成set里面有的最近的目标余数,所以就取set里面第一个,比如5%3==2,2是原余数,找到最近的目标余数这样进行操作的次数就会最少,如果目标余数里面还有2的话,就不要进行加操作了,直接取目标余数就好了,但是现在目标余数没有2了,最大只有1
,所以我们目标余数取0(如果0还有的话,反正取set里面第一个(set默认升序)),取第一个的概念:有点环的概念
取过的目标余数就标记一下,满足了出现n/m次就从set里面删除
#include <iostream> #include <cstdio> #include<stdio.h> #include<algorithm> #include<cstring> #include<math.h> #include<memory> #include<queue> #include<vector> #include<set> using namespace std; typedef long long LL; #define max_v 200005 int n,m; LL a[max_v]; LL c[max_v]; LL sum; int main() { while(~scanf("%d %d",&n,&m)) { set<int> s; set<int>::iterator it; memset(c,0,sizeof(c)); sum=0; for(int i=0;i<m;i++) s.insert(i); for(int i=1;i<=n;i++) { scanf("%lld",&a[i]); int x=a[i]%m; int y; if(x>*s.rbegin())//s中删除某个后,可能余数会大于s里面最大的,那么余数肯定选择s里面第一个 y=*s.begin(); else y=*s.lower_bound(x);//大于等于x的第一个 c[y]++;//标记位加1 if(c[y]==n/m)//该余数用过了n/m次 s.erase(y);//删除用过了n/m次的余数 a[i]+=((y-x)+m)%m; sum+=((y-x)+m)%m; } printf("%lld\n",sum); for(int i=1;i<=n;i++) printf("%lld ",a[i]); printf("\n"); } return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南