1,题目描述:
D,使余数相等。
给你一个含有n个整数的数组a1,a2,…,an,和一个正整数m。保证m是n的因数。
在单次移动中,你可以选择在1到n之间的任一位置的数ai加1.
计算cr(0~m-1)——每个元素除以m之后的余数r。换句话说,对于每个余数,
找到与它相对应的元素。
你的任务是改变数组的元素使得c0=c1=…=cm-1=n/m;
找到满足上述要求的最小的需要改变的次数
输入:
第一行包括两个整数n,m(1~2e5,1<=m<=n)保证m是n的因数。
第二行是n个整数a1,a2,…an(0~1e9)
输出:
第一行,输出第一行——最小需要移动的数字满足下面的情况。对于任一个余数
(0~m-1),数组中的元素都有一个余数等于n/m。
第二行,输出任一数组满足条件的。可以从原数组中得到的最小的改变的次数。结果
数组中的所有结果不超过1e18.
(翻译完题目我整个人是很懵逼的,我理解题意用了好久好久好久。。。。。
最后get到:原来是0~m-1的余数的所有个数都相等等于n/m)
2,problem link:
http://codeforces.com/contest/999/problem/D
3,AC code:
代码注释:
*类型:贪心
#include<iostream>
#include<algorithm>
#include<set>
using namespace std;
typedef long long ll;
const int N=2e5+6;
set<ll>st;
//cnt数组用来存0~m-1位置的所有的余数的个数都为n/m
//arr数组用来存输入的数组,以及改变后的数组
//res用来存当前值的余数
//val用来存应该最优应该选取的余数的值。
//ans用来存需要改变的操作数
ll n,m,cnt[N],arr[N],res,val,ans;
int main(){
cin>>n>>m;
for(int i=0;i<m;cnt[i++]=n/m)st.insert((ll)i);
for(int i=0;i<n;i++){
cin>>arr[i];
res=arr[i]%m;
//贪心部分
if(res>*st.rbegin())val=*st.begin();
else val= *st.lower_bound(res);
//贪心部分
ans=ans+(val-res+m)%m;
if(!--cnt[val])st.erase(val);
arr[i]=arr[i]+(val-res+m)%m;
}
cout<<ans<<endl;
for(int i=0;i<n;i++)cout<<arr[i]<<" ";
}