Problem
一个车牌号由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)使得 xi<yixi<yi 并且 xj=yjxj=yj ,那么我们就说x比y小。
Solution
0到9循环,每次排序改变前面的。
排序规则,先排差绝对值小的,相等先排数大的,这样字典序会改小,数还相等,如果小于当前循环的i,说明字典序会变大,就先排后面的,否则先排前面的。
Code
#include<iostream> #include<cstdio> #include<string> #include<cstring> #include<algorithm> #define io_opt ios::sync_with_stdio(false);cin.tie(0);cout.tie(0) using namespace std; int n,k; struct E{ char c; int pla; }e[10020]; E ans[10020]; E cur[10020]; int mn=1e9; bool Ecmp(E x[],E y[]){ for(int i=1;i<=n;i++){ if(x[i].c<y[i].c) return false; else if(x[i].c>y[i].c) return true; } return false; } void cpy(E x[],E y[]){ for(int i=1;i<=n;i++){ x[i]=y[i]; } } string s; int tmp=0; int ab(int x){ return x>0?x:-x; } int cmp(E x,E y){ int xx=x.c-'0',yy=y.c-'0'; if(ab(xx-tmp)==ab(yy-tmp)){ if(xx==yy){ if(xx>tmp){ return x.pla<y.pla; //cout<<x.pla<<" before "<<y.pla<<endl; } else{ return x.pla>y.pla; //cout<<x.pla<<" after "<<y.pla<<endl; } } else{ return xx>yy; } } return ab(xx-tmp)<ab(yy-tmp); } int cmp2(E x,E y){ return x.pla<y.pla; } int main(){ io_opt; cin>>n>>k; cin>>s; for(int i=0;i<n;i++){ e[i+1].c=s[i]; e[i+1].pla=i+1; } int cmn; for(int i=0;i<=9;i++){ cmn=0; cpy(cur,e); tmp=i; sort(cur+1,cur+1+n,cmp); for(int j=1;j<=k;j++){ cmn+=ab(cur[j].c-'0'-i); cur[j].c='0'+i; } /*if(i==2){ for(int j=1;j<=n;j++){ cout<<cur[j].pla<<' '; } cout<<endl; }*/ sort(cur+1,cur+1+n,cmp2); if(cmn<mn||cmn==mn&&!Ecmp(cur,ans)){ mn=cmn; for(int j=1;j<=n;j++){ ans[j]=cur[j]; } } } cout<<mn<<endl; for(int i=1;i<=n;i++){ cout<<ans[i].c; } cout<<endl; return 0; }