http://codeforces.com/contest/118/problem/C
题意:给n长度的串,要求通过一系列替换操作,至少要有k个数字相同。
替换的代价为原数字到新数字的绝对值
那么我们直接枚举替换为0-9的方案,每次算出每个数字替换为i 的代价,
然后按代价从小到大排序,代价相同的 按 【改变了该数字为i 字典序会变大还是变小排序】(主要这里写好了就OK了)
最后选择一个总代价最小的输出,如果有多个,选字典序最小的输出。
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <iostream>
using namespace std;
const double pi=acos(-1.0);
double eps=0.000001;
int tm[10005];
struct node
{
int x,id;
int val;
};
node ss[10005];
int cur=-1;
bool cmp(node a,node b)
{
if (a.val!=b.val) //优先按代价排序
return a.val<b.val;
if (a.id<b.id) //代价相同时,看位置,优先考虑前面的
{
if ( a.x>cur) //如果原数字大于新数字i,则字典序变小,符合
return true;
else if (a.x<cur) return false; //否则字典序变大,不符合
if (a.x==cur) //当前一个数字不改变字典序时,考虑后一个
{
if (b.x>cur) return false; //字典序变小,则优先修改b
else return true; //字典序变大或不变,不需要交换
}
}
else
{
if ( b.x>cur) //同理,先考虑在前面的,再考虑后面的
return false;
else if (b.x<cur) return true;
if (b.x==cur)
{
if (a.x>=cur) return true;
else return false;
}
}
}
bool cmp22(node a,node b)
{
return a.id<b.id;
}
int ans[12][10005];
int sum[12];
int main()
{
int i,j;
int n,k;
cin>>n>>k;
for (i=1; i<=n; i++) scanf("%1d",&tm[i]);
int minn=10000*20;
int mini=-1;
for (i=0; i<=9; i++)
{
cur=i;
for(j=1; j<=n; j++)
{
ss[j].x=tm[j]; //原数字
ss[j].id=j; //位置序号
ss[j].val=abs(tm[j]-i); //记录代价
}
sort(ss+1,ss+1+n,cmp); //按代价从小到大排序,代价相同的 按 【改变了该数字为i 字典序会变大还是变小排序】
for (j=1; j<=k; j++)
{
sum[i]+=ss[j].val; //累计代价
ss[j].x=i; //替换数字
}
sort(ss+1,ss+1+n,cmp22); //恢复原位置
for (j=1; j<=n; j++) //存储答案
ans[i][j]=ss[j].x;
if (sum[i]<minn)
minn=sum[i];
}
queue<int>sb;
for (i=0; i<=9; i++) //选择最小代价的
{
if (minn==sum[i])
sb.push(i);
}
int xx=sb.front();
sb.pop();
while(!sb.empty()) //多个最小代价取字典序最小的
{
int tp=sb.front();
sb.pop();
int flag=0;
for (i=1; i<=n; i++)
{
if (ans[xx][i]<ans[tp][i])
{
flag=-1;
break;
}
else if (ans[xx][i]>ans[tp][i])
{
flag=1;
break;
}
}
if (flag==1) xx=tp;
}
printf("%d\n",sum[xx]);
for (i=1; i<=n; i++)
printf("%d",ans[xx][i]);
printf("\n");
return 0;
}