大体题意:
给你n 个数,要求1~m每个数出现次数的最小值尽可能大,要求你修改n个数,要改的次数尽可能小,输出最小值的最大可能和最少修改次数,并把改的数组输出出来!
思路:
开始没看到次数尽可能少,wa了一次!
想一想就知道,最大可能值肯定是 n/m
那么直接统计1~m 每个数出现了几次!
然后枚举一遍a数组,如果当前值 在1~m范围内!就判断这个数的出现次数 如果小于等于n/m 肯定不用管!
如果大于n/m 那么就枚举一遍1~m 看哪个数 还不足 n/m 就给它加上!
如果不在1~m范围内 同样的方式处理。
时间复杂度 o(nm)
详细见代码:
#include <bits/stdc++.h>
#define ps push_back
#define fi first
#define se second
using namespace std;
const int maxn = 2000 + 10;
const double eps = 1e-10;
const int inf = 0x3f3f3f3f;
typedef long long ll;
typedef unsigned long long ULL;
ll a[maxn],b[maxn];
int num[maxn];
int main(){
int n,m;
scanf("%d %d",&n,&m);
for (int i = 1; i <= n; ++i){
scanf("%I64d",&a[i]);
if (a[i] <= m)
num[a[i]]++;
}
int t = n/m;
for (int i = 1; i <= n; ++i){
b[i] = a[i];
if (a[i] <= m){
if (num[a[i]] <= t)continue;
else {
bool ok = 0;
for (int j = 1; j <= m; ++j){
if (num[j] < t){
ok = 1;
b[i] = j;
num[j]++;
num[a[i] ]--;
break;
}
}
if (!ok)continue;
}
}
else {
bool ok = 0;
for (int j = 1; j <= m; ++j){
if (num[j] < t){
ok = 1;
b[i] = j;
num[j]++;
// num[a[i] ]--;
break;
}
}
if (!ok)continue;
}
}
int ans = 0;
for (int i = 1; i <= n; ++i){
if (a[i] != b[i]) ++ans;
}
printf("%d %d\n",t,ans);
for (int i =1 ; i <= n; ++i){
if (i > 1)printf(" ");
printf("%d",b[i]);
}
puts("");
return 0;
}