最小表达式E
牛客网题目地址
描述:
给出一个包含数字1-9和加号的字符串,请你将字符串中的字符任意排列,但每种字符数目不变,使得结果是一个合法的表达式,而且表达式的值最小。输出那个最小表达式的值
合法的表达式的定义如下:
-
一个数字,如233,是一个合法的表达式
-
A + B是合法的表达式,当且仅当 A , B 都是合法的表达式
保证给出的表达式经过重排,存在一个合法的解。
输入描述:
一行输入一个字符串,仅包含数字1-9和加号+。
字符串的长度小于5*10^5
输出描述:
一行输出一个数字,代表最小的解。
输入
23984692+238752+2+34+
输出
5461
/*
我们拥有的可以放数字的数位的权值分别是1,1,1,1,1,...,1,10,10,10,10,...,10,100,...
(每种各加号个数加一个),于是只需要贪心的将大的数字放到小权值的数位上即可。
考虑题目中的第四个样例:23984692+238752+2+34+
这个样例的数字排序后为['2', '2', '2', '2', '2', '3', '3', '3', '4', '4', '5', '6', '7', '8', '8', '9', '9'],
加号有四个,则意味着我们要建立五个数字。
每个数字从后向前添加数位,则先添加个位数,十位数,再添加百位数,等等等等。
并且我们一定是按照顺序添加,不可能在个位数尚有未填写的情况去填另一个数字的百位数,
因为不优。答案为
2369+2359+248+248+237=5461
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int cnt[20];
int sum[500050];
char s[500050];
int main() {
cin>>s;//下面代码以23984692+238752+2+34+为例
int ccnt = 1;
int n = strlen(s);
for(int i=0;i<n;i++){
if(isdigit(s[i])){//isdigit函数 若参数c为阿拉伯数字0~9,则返回非0值,否则返回0。
cnt[s[i]-'0']+=1;//字符变整数 cnt[2]=5 cnt[3]=3 cnt[4]=2.... 表示有5个2,3个3,2个4
}else{
ccnt+=1;//一共要有几位数
}
}
int p = 0,cp = 0;
for(int i=10;i>=1;i--){
while(cnt[i]){
sum[cp]+=i;//位数相同的每一位的和 从低位算起 sum[0]=9+9+8+8+7=41
cnt[i]-=1;//个数少1
p = (p+1)%ccnt;//判断位数是否需要变成高位
if(p == 0)
cp+=1;
}
}
for(int i=0;i<500010;i++){//计算最小和
sum[i+1]+=sum[i]/10;//低位向高位进位 sum[1]=sum[1]+sum[0]/10 sum[1]=22+4=26
sum[i]%=10;//第i位的值 sum[0]=sum[0]%10=41%10=1
}
int opt = 0;
for(int i=500010;i>=0;i--){
if(opt || sum[i]){
cout<<sum[i];//输出各个位数上的值 sum[0]=1,所以最低位为1
opt = 1;
}
}
cout<<endl;
return 0;
}