51nod1621 花钱买车牌 排序+贪心

本文介绍了一种算法问题,旨在找到更改车牌号码以达到特定美观标准所需的最小成本,并确保输出的新车牌号码字典序最小。该问题通过枚举和排序等方法解决。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目来源: CodeForces
基准时间限制:1 秒 空间限制:131072 KB 分值: 20 难度:3级算法题
收藏
关注

一个车牌号由n位数字组成。如果一个车牌至少有k位数字是相同的,那么我们就说这个车牌漂亮的车牌。现在华沙想要改变他自己的车牌,使得他的车牌变得漂亮。当然,改车牌是要花钱的。每改变一位数字所要花费的费用等于当前位上的新旧数字之差的绝对值。那么总费用就是每位上所花费用的总和。

举例如下,

旧牌为0123,新牌为7765,那么对应第一位所花费用为|0-7|7,第二位为|1-7|6,第三位为|2-6|4,第四位为|3-5|2,总和为7+6+4+219

华沙想用最少的钱,使他的车牌变得漂亮起来。现在给定nk,和旧牌的号码,计算换牌的最少费,以及新牌的号码,

如果最少费用的号码有多个,我们取字典序最小的那个。


样例解释:


在样例中,把第二个数字换成“8”花费|9-8|1,把第五个数字换成“8”也花了1。

把第六个数字换成“8”花费|6-8|2.总费用为1+1+24,新号码为“888188

 

两个长度为n的序列比较方法如下。

存在两个序列xy,长度都是n

如果存在i(1in)和任意j(1ji)使得  xiyi  并且  xjyj  ,那么我们就说xy小。





Input


单组测试数据第一行,两个由空格隔开的数字n和k(2≤n≤10^4,2≤k≤n),表示旧牌的位数,和至少要有k位数字相同才能构成漂亮的车牌。第二行有n位数字,代表华沙的旧车牌。(旧车牌中只有数字)。


Output


共两行,第一行,一个整数,代表换牌的最小费用,第二行,n位数字,表示新的车牌。如果最小费用的车牌有多个,输出字典序最小的那个。


Input示例


6 5898196


Output示例


4888188


思路:枚举最佳方案是0-9其中的一个数,然后就是排序的小细节(只为字典序)。细细揣摩。
Code:
#include <bits/stdc++.h>
#define INF 12345678
using namespace std;
const int AX = 1e4+66;
int n , k ;
char s[AX];
int a[AX];
struct Node
{
	int v;
	int id;
	int val;
	bool f;
}ans[AX];
bool cmp( const Node &a , const Node &b ){
	if( a.v != b.v ) return a.v < b.v;
	else if( a.val != b.val ) return a.val > b.val;
	else {
		if( a.f ) return a.id < b.id;
		else return a.id > b.id;
	} 
}
int main(){
	scanf("%d%d",&n,&k);
	scanf("%s",s);
	int falg = 1 ;
	memset(a,0,sizeof(a));
	for( int i = 0 ; i < n ; i++ ){
		a[s[i]-'0'] ++ ;
		if( a[s[i]-'0'] >= k ){
			falg = 0;
		}
	}

	if( falg ){
		int val;
		int coss = -1 ;
		char res[AX];  
		for( int jj = 0 ; jj <= 9 ; jj++ ){
			val = jj;
			for( int i = 0 ; i < n ; i++ ){
				ans[i].v = abs( (s[i]-'0') - val);
				ans[i].id = i;
				ans[i].val = s[i]-'0';
				ans[i].f = ( (s[i]-'0') > val ? true : false );
			}
			int cost = 0;
			sort( ans , ans + n , cmp );
			int kk = k - a[val];
			for( int i = 0 ; i < n ;i++ ){
				if( kk == 0 ) break;
				if( s[ans[i].id] == (val+'0') ) continue;
				else{
					kk--;
					cost += ans[i].v;
					ans[i].val = val;
				}
			}
			char tmp[AX];
			for( int i = 0 ; i < n ; i++ ){
				int index = ans[i].id;
				tmp[index] = (char)(ans[i].val+'0');
			}
			if( coss != -1 ){
				if( cost < coss ){
					coss = cost;
					for( int i = 0 ; i < n ; i++ ){
						res[i] = tmp[i];
					}
				}else if( coss == cost ){
					if( strcmp( res , tmp ) > 0 ){
						for( int i = 0 ; i < n ; i++ ){
							res[i] = tmp[i];
						}
					}
				}
			}else{
				coss = cost;
				for( int i = 0 ; i < n ; i++ ){
					int index = ans[i].id;
					res[index] = (char)(ans[i].val + '0');
				}
			}
		}
		cout << coss << endl;
		for( int i = 0 ; i < n ; i++ ){
			cout << res[i];
		}
		cout << endl;
	}else{
		printf("0\n");
		printf("%s\n",s);		
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值