牛客3005E-最小表达式-大数运算

链接: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;
}
发布了144 篇原创文章 · 获赞 135 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/Nothing_but_Fight/article/details/104268056