洛谷P8482 Number 题解

原题戳这!

如何求最大乘积

我们令 n u m 1 num1 num1 为前几位较大的数, n u m 2 num2 num2 为前几位相对较小的数。

浅浅地证明

首先我们肯定得使高位尽可能大,那么在高位都尽可能大的情况下,两个数的和基本相同的,我们用小学求周长相同,求最大矩形面积的方法,可以知道,当两数差最小时,乘积最大。

构造方法

根据上述原则,我们可以开始构造了。

当两数数位相同且前几位相同时,为了保证 n u m 1 num1 num1 前几位尽可能大,我们就将最大位给 n u m 1 num1 num1 即可。数位不一样,那就哪个少给哪个。当两数数位相同但数不相同时,此时 n u m 1 num1 num1 的前几位已经比 n u m 2 num2 num2 大了,故将大的给 n u m 2 num2 num2 以保证两数差距最小。

结合代码理解一下

Code 1

tot1=tot/2; //num1的数位 
	tot2=tot/2+(tot&1);//num2的数位,若是奇数则将多余的给num2 
	int k1=0,k2=0,la1=0,la2=0;//k是已分配的位数,la是前几位相同的最后一位或者第一个不相同的那位的值 
	for(re int i=9;i>=0;--i){
		for(;a[i];){           //num1,num2都是用队列存的
			if(k1==tot1)num2.push(i),a[i]--,k2++; //若已经达到了位数就不加了 
			else if(k2==tot2)num1.push(i),a[i]--,k1++;
			else if(k1==k2){//如果数位相同,那就看前几位相同不相同 
				if(la1==la2){
					num1.push(i),a[i]--,k1++,la1=i;
					if(a[i])num2.push(i),a[i]--,k2++,la2=i;//相同就给1 
					else{
						for(;!a[i]&&i>=0;)--i;
						if(i>=0)num2.push(i),a[i]--,k2++,la2=i;//给2 
					}
				}
				else num2.push(i),a[i]--,k2++;
			}else if(k1>k2)num2.push(i),a[i]--,k2++;//谁少了给谁 
			else if(k1<k2)num1.push(i),a[i]--,k1++;
		}
	}

恭喜你,拿到了 50 50 50 分!

如何构造

在我打算放弃之际,我看见了题面中我的救星。

1 ≤ c i 1\le c_i 1ci

这意味着什么?意味着一定有 0 0 0 存在,也就是其中一个数一定可以被10整除。

根据我们上面的贪心策略, 0 0 0 一定被放在了末位,那么我们只需要将有 0 0 0 的那个数去掉末尾的 0 0 0 ,然后再给任意一个数乘 5 5 5,另外一个数乘 2 2 2即可。

注意数据很大,得用高精。

其实乘 2 2 2 2 2 2,乘 5 5 5 5 5 5 等方法都能合理构造,只不过作者太懒不想多写一个高精除。

Code

#include<bits/stdc++.h>
using namespace std;
#define re register
inline int read(){
	int x=0;char c=getchar();
	for(;!isdigit(c);c=getchar());
	for(;isdigit(c);c=getchar())x=(x<<3)+(x<<1)+(c^48);
	return x;
}
int a[10],tot;
queue<int>num1,num2;
int tot1,tot2;
int x[10000005],y[10000005];
inline void chen(int b[],int &g,int v,int k){
	for(re int i=k;i<=g;++i){
		b[i]*=v;
	}
	for(re int i=k;i<=g;++i){
		b[i+1]+=b[i]/10;
		b[i]%=10;
	}
	for(;b[g+1]||b[g+2];)g++;
	return;
}
int main(){
	for(re int i=0;i<=9;++i){
		a[i]=read();
		tot+=a[i];
	}
	tot1=tot/2; //num1的数位 
	tot2=tot/2+(tot&1);//num2的数位,若是奇数则将多余的给num2 
	int k1=0,k2=0,la1=0,la2=0;//k是已分配的位数,la是前几位相同的最后一位或者第一个不相同的那位的值 
	for(re int i=9;i>=0;--i){
		for(;a[i];){           //num1,num2都是用队列存的
			if(k1==tot1)num2.push(i),a[i]--,k2++; //若已经达到了位数就不加了 
			else if(k2==tot2)num1.push(i),a[i]--,k1++;
			else if(k1==k2){//如果数位相同,那就看前几位相同不相同 
				if(la1==la2){
					num1.push(i),a[i]--,k1++,la1=i;
					if(a[i])num2.push(i),a[i]--,k2++,la2=i;//相同就给1 
					else{
						for(;!a[i]&&i>=0;)--i;
						if(i>=0)num2.push(i),a[i]--,k2++,la2=i;//给2 
					}
				}
				else num2.push(i),a[i]--,k2++;
			}else if(k1>k2)num2.push(i),a[i]--,k2++;//谁少了给谁 
			else if(k1<k2)num1.push(i),a[i]--,k1++;
		}
	}
	for(re int i=1;i<=tot1;++i){
		x[tot1-i+1]=num1.front();
		num1.pop();
	}
	for(re int i=1;i<=tot2;++i){
		y[tot2-i+1]=num2.front();
		num2.pop();
	}
	k1=1,k2=1;//起始位置 
	if(x[1]==0)k1++;//只需去掉一个0,也就是将起始位置加一 
	else if(y[1]==0)k2++;
	chen(x,tot1,2,k1);//高精不多说了 
	chen(y,tot2,5,k2);
	for(re int i=tot1;i>=k1;--i){
		printf("%d",x[i]);
	}
	puts("");
	for(re int i=tot2;i>=k2;--i){
		printf("%d",y[i]);
	}
	return 0;
}

恭喜你,满分了!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值