链接:https://ac.nowcoder.com/acm/contest/3005/E
来源:牛客网
题目描述:
给出一个包含数字1-9和加号的字符串,请你将字符串中的字符任意排列,但每种字符数目不变,使得结果是一个合法的表达式,而且表达式的值最小。输出那个最小表达式的值
合法的表达式的定义如下:
-
一个数字,如233,是一个合法的表达式
-
A + B是合法的表达式,当且仅当 A , B 都是合法的表达式
保证给出的表达式经过重排,存在一个合法的解。
输入描述:
一行输入一个字符串,仅包含数字1-9和加号+。
字符串的长度小于5∗105。
输出描述:
一行输出一个数字,代表最小的解。
输入样例:
111+1
输出样例:
22
核心思想:
将加号的个数记为jia。
位数越多,数值越大,应该将数字个数尽量平分给jia+1个子式,让小的数字再高位,大数字在低位。得到jia+1个子式后,用大数运算的思想加和求解。
代码如下:
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=5e5+20;
int sum[N],num[12];//sum存最终数值,num[i]表示数字i出现的次数
string s[N];//存jia+1个子式
char str[N];//原字符串
int main()
{
int jia=0;
scanf("%s",str);
int len=strlen(str);
for(int i=0;i<len;i++)
{
if(str[i]=='+')
jia++;
else
num[str[i]-'0']++;
}
int yu=(len-jia)%(jia+1);//长度为z+1的子式个数
int z=(len-jia)/(jia+1);//较短子式长度为z,较长的为z+1
int pos=1;//赋值用的指针
for(int u=1;u<10;u++)
{
for(int i=0;i<num[u];i++)
{
if(pos>jia+1)pos=1;//赋值完成一轮,进行下一轮
s[pos]+=u;//string特性,直接+=运算即可
pos++;//指针指向下一个子式
}
}
for(int i=z-1;i>=0;i--)//大数运算思想,将子式(大数)相加
{
for(int j=1;j<=yu;j++)
sum[z-i]+=s[j][i+1];
for(int j=yu+1;j<=jia+1;j++)
sum[z-i]+=s[j][i];
}
for(int i=1;i<=yu;i++)//长度为z+1的子式的最高位也要加起来
sum[z+1]+=s[i][0];
int en=N-5;
for(int i=1;i<en;i++)
{
sum[i+1]+=sum[i]/10;
sum[i]%=10;
}
int k=en;
while(!sum[k])k--;//寻找ans的最高位
for(int i=k;i>0;i--)
printf("%d",sum[i]);
cout<<endl;
return 0;
}