其他分享
首页 > 其他分享> > 20200628 T1 幸运号码

20200628 T1 幸运号码

作者:互联网

题目描述

小 \(\text{L}\) 刚买了一辆新车,还申请到了一个长 \(n\) 位的车牌号。对于一个意义如此重大的号码,小 \(\text{L}\) 当然希望他能是自己的幸运号码了。

小 \(\text{L}\) 认为,一个数字串是幸运号码,当且仅当它包含至少 \(k\) 个相同的数位。假如车牌号不是幸运号码,可以进行修改,只是要付出一些费用;具体来说,每修改车牌号当中的某一位,要付的费用等于修改前后这一位之差的绝对值。

小 \(\text{L}\) 希望能花尽可能少的钱来把车牌号改成幸运号码,但 \(\text{TA}\) 发现这个问题有些棘手,于是 \(\text{TA}\) 向你求助。

你需要给出一个花费最小的修改方案,在此前提下,小 \(\text{L}\) 还希望最终的车牌号字典序尽可能小。

输入格式

第一行包含两个正整数 \(n\) 和 \(k\),表示这牌好的长度和幸运号码的条件。

第二行包含一个长度为 \(n\) 的数字串,表示初始时的车牌号。

输出格式

第一行输出一个非负整数,表示修改车牌号的最小花费;第二行输出在此基础上字典序最小的修改方案。

样例

1.in

6 5
898196

1.out

4
888188

2.in

3 2
533

2.out

0
533

数据范围与约定

对于 \(30\%\) 的数据, \(n \leq 5\);

对于 \(100\%\) 的数据,\(2 \leq k \leq n \leq 10^5\)。

题解

贪心。考虑在更改完的串中出现了 \(k\) 次的是那个字符(\(0 \sim 9\) 枚举即可),记作 \(a\)。
需要满足费用最小,所以枚举要更改的数 \(b\) 与 \(a\) 的绝对值 \(c\)(\(1 \sim ...\),有个界限,\(0 \leq b \leq 9\)),这样按顺序更改即可满足费用最小。
需要满足字典序最小,所以对于同一个 \(c\) 要先将原串中的 \(a + c\) 从前往后(这样满足字典序最小),改成 \(a\),再将 \(a - c\) 从后往前(这样满足字典序最小)改成 \(a\) 。

Code

#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>
#define MAXN 100001

int n, k, num[11];
std::string sss;
int minn = 2147483647, ans;
char a[MAXN];

int max(int a, int b) { return a > b ? a : b; }

int main() {
	//freopen("number.in", "r", stdin);
	//freopen("number.out", "w", stdout);
	scanf("%d %d", &n, &k);
	std::cin >> sss;
	int len = sss.length();
	for (int i = 0; i < len; ++i) {
		++num[sss[i] - '0'];
		a[i] = sss[i];
	}
	for (int i = 0; i < 10; ++i) {
		int opt = k - num[i], bz = 0;
		int stop = max(9 - i, i);
		for (int j = 1; j <= stop && opt; ++j) {
			int b = i - j, c = i + j;
			if (c <= 9 && opt) {
				if (num[c] <= opt) {
					opt -= num[c];
					bz += (c - i) * num[c];
				}
				else {
					bz += (c - i) * opt;
					opt = 0;
				}
			}
			if (b >= 0 && opt) {
				if (num[b] <= opt) {
					opt -= num[b];
					bz += (i - b) * num[b];
				}
				else {
					bz += (i - b) * opt;
					opt = 0;
				}
			}
		}
		if (minn > bz) minn = bz, ans = i;
	}
	int opt = k - num[ans], stop = max(9 - ans, ans);
	for (int i = 1; i <= stop && opt; ++i) {
		int b = ans - i, c = ans + i;
		if (c <= 9 && opt) {
			for (int j = 0; j < len && opt; ++j) {
				if (sss[j] == c + '0') {
					a[j] = ans + '0';
					--opt;
				}
			}
		}
		if (b >= 0 && opt) {
			for (int j = len - 1; j >= 0 && opt; --j) {
				if (sss[j] == b + '0') {
					a[j] = ans + '0';
					--opt;
				}
			}
		}
	}
	std::cout << minn << '\n';
	std::cout << a << '\n';
	fclose(stdin), fclose(stdout);
	return 0;
}

标签:20200628,opt,号码,int,text,车牌号,T1,leq,sss
来源: https://www.cnblogs.com/poi-bolg-poi/p/13204997.html