一个车牌号由n位数字组成。如果一个车牌至少有k位数字是相同的,那么我们就说这个车牌漂亮的车牌。现在华沙想要改变他自己的车牌,使得他的车牌变得漂亮。当然,改车牌是要花钱的。每改变一位数字所要花费的费用等于当前位上的新旧数字之差的绝对值。那么总费用就是每位上所花费用的总和。
举例如下,
旧牌为0123,新牌为7765,那么对应第一位所花费用为|0-7|=7,第二位为|1-7|=6,第三位为|2-6|=4,第四位为|3-5|=2,总和为7+6+4+2=19
华沙想用最少的钱,使他的车牌变得漂亮起来。现在给定n,k,和旧牌的号码,计算换牌的最少费,以及新牌的号码,
如果最少费用的号码有多个,我们取字典序最小的那个。
样例解释:
在样例中,把第二个数字换成“8”花费|9-8|=1,把第五个数字换成“8”也花了1。
把第六个数字换成“8”花费|6-8|=2.总费用为1+1+2=4,新号码为“888188”
两个长度为n的序列比较方法如下。
存在两个序列x,y,长度都是n。
如果存在i(1≤i≤n)和任意j(1≤j<i)使得 x i <y i 并且 x j =y j ,那么我们就说x比y小。
Input
单组测试数据
第一行,两个由空格隔开的数字n和k(2≤n≤10^4,2≤k≤n),表示旧牌的位数,和至少要有k位数字相同才能构成漂亮的车牌。
第二行有n位数字,代表华沙的旧车牌。(旧车牌中只有数字)。
Output
共两行,
第一行,一个整数,代表换牌的最小费用,
第二行,n位数字,表示新的车牌。
如果最小费用的车牌有多个,输出字典序最小的那个。
Input示例
6 5
898196
Output示例
4
888188
分析:枚举+贪心: 枚举x为重复数字,然后每次修改离x绝对值最近的数,记录每个数字出现的下标,然后注意修改时的顺序就行。
#include<iostream>
#include<stdio.h>
#include<stack>
#include<string.h>
#include<algorithm>
#include<vector>
const int maxn = 20000;
const int inf = 1e9;
typedef long long ll;
using namespace std;
int n,sk,bit[15][maxn+5],num[15],to[maxn+5],a[maxn+5];
char S[maxn+5],f[maxn+5],ch[maxn+5];
int work(int v)
{
int cost = 0,cnt=0,s=1,l=v-1,r=v+1;
while(s<=num[v]&&cnt<sk) to[bit[v][s]]=1,s++,cnt++;
strcpy(ch,S);
if(cnt==sk) return cost;
while(cnt<sk)
{
s=1;
while(r<10&&s<=num[r]&&cnt<sk) to[bit[r][s]]=1,s++,cnt++,cost+=r-v;// 因为要最小序 所以先把数字大的改成v 字典序会变小
if(l>=0) s=num[l];// 因为改变成v 会使字典序变大 所以这里要从下标在后面的开始改变
while(l>=0&&s>=1&&cnt<sk) to[bit[l][s]]=1,s--,cnt++,cost+=v-l;
r++,l--;
}
for(int i=0; i<n; i++)
{
if(to[i]) ch[i] = '0'+v;
}
return cost;
}
int main()
{
while(~scanf("%d %d",&n,&sk))
{
for(int i=0; i<=10; i++) num[i] = 0;
scanf("%s",S);
for(int i=0; i<n; i++) bit[S[i]-'0'][++num[S[i]-'0']]=i;
int ans = inf;
for(int v=0; v<10; v++)
{
for(int j=0; j<n; j++) to[j] = 0;
int cost = work(v);
if(cost<ans||(ans==cost&&(strcmp(ch,f)<0))) ans = cost,strcpy(f,ch);
}
printf("%d\n%s\n",ans,f);
}
}