UOJ #553. 第一饭堂

【题目描述】:

已知第一饭堂饭菜的价格有N位(坑爹吧!),如果一个价格有不小于K个数位完全相同,那么这个数字就被认为是漂亮的,否则这个数字被认为是不漂亮的。饭堂班长想改变其中一个饭菜的价格,改变价格中的一位需要花费一些钱,所需费用是这一位改变量之差的绝对值。

饭堂班长希望你能把这个价格变漂亮,求出最小费用,同时给出字典序最小的一个方案。

【输入描述】:

第1行:两个用空格隔开的数字N和K(2≤n≤10^4, 2≤k≤n)。

第2行:一个N位的数字表示原来的价格。

【输出描述】:

第1行:最小费用。

第2行:所求方案。

【样例输入1】:

6 5
898196

【样例输出1】:

4
888188

【样例输入2】:

3 2
533

【样例输出2】:

0
533

【样例输入3】:

10 6
0001112223

【样例输出3】:

3
0000002223

【时间限制、数据范围及描述】:

时间:1s 空间:256M 10%的数据:N≤5;

20%的数据:N≤10;

30%的数据:N≤18;

70%的数据:N≤500;

对于100%的数据,2≤N≤10000,2≤k≤n。

思路:

记录s(原价)中0~9的个数,然后从0开始贪心(贪最小字典序),每算出一种答案比较一次,以防出现非最优解的情况

代码:

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

string fin,s,tmp;
int n,k,i,j,t,ans1,ans,a[10];

void change(string &s,int x,int y) {
	int i;
	if (x>y)
		for(int i=0; i<n; i++)
			if(s[i]==x+'0') {
				t--;
				s[i]=y+'0';
				ans1+=abs(y-x);
				if(!t)
					break;
			}
	if(x<y)
		for(int i=n-1; i>=0; i--)
			if(s[i]==x+'0') {
				t--;
				s[i]=y+'0';
				ans1+=abs(y-x);
				if(!t)
					break;
			}
}

int main() {
	scanf("%d%d",&n,&k);
	cin>>s;
	for(int i=0; i<n; i++)
		a[s[i]-'0']++;
	ans=int(1e9);
	fin=s;
	for(int i=0; i<10; i++) {
		t=k-a[i],ans1=0;
		tmp=s;
		if (t>0)
			for(int j=1; j<=9; j++) {
				if(i+j<10)
					change(tmp,i+j,i);
				if(!t)
					break;
				if(i-j>=0)
					change(tmp,i-j,i);
				if(!t)
					break;
			}
		if(ans1<ans) {
			ans=ans1;
			fin=tmp;
		} else if(ans1==ans&&tmp<fin)
			fin=tmp;
		/*printf("%d\n",ans);
		cout<<fin<<endl;*/
	}
	printf("%d\n",ans);
	cout<<fin<<endl;
	return 0;
}

 

posted @ 2019-08-21 00:27  双子最可爱啦  阅读(144)  评论(0编辑  收藏  举报