541 最强DE 战斗力【数学和大数处理】

最强DE 战斗力

时间限制: 1000 ms  |  内存限制: 65535 KB
难度: 3
描述

春秋战国时期,赵国地大物博,资源非常丰富,人民安居乐业。但许多国家对它虎视眈眈,准备联合起来对赵国发起一场战争。

显然,面对多个国家的部队去作战,赵国的兵力明显处于劣势。战斗力是决定战争成败的关键因素,一般来说,一支部队的战斗力与部队的兵力成正比。但当把一支部队分成若干个作战队伍时,这个部队的战斗力就会大大的增强。

一支部队的战斗力是可以通过以下两个规则计算出来的:

1.若一支作战队伍的兵力为N,则这支作战队伍的战斗力为N;

2.若将一支部队分为若干个作战队伍,则这支部队的总战斗力为这些作战队伍战斗力的乘积。

比如:一支部队的兵力为5时的战斗力分析如下:

情况

作战安排

总的战斗力

1

1,1,1,1,1(共分为5个作战队伍)

1*1*1*1*1=1

2

1,1,1,2   (共分为4个作战队伍)

1*1*1*2=2

3

1,2,2     (共分为3个作战队伍)

1*2*2=4

4

1,1,3     (共分为3个作战队伍)

1*1*3=3

5

2,3        (共分为2个作战队伍)

2*3=6

6

1,4        (共分为2个作战队伍)

1*4=4

7

5           (共分为1个作战队伍)

5=5

    显然,将部队分为2个作战队伍(一个为2,另一个为3),总的战斗力达到最大!
输入
第一行: N表示有N组测试数据. (2<=N<=5)
接下来有N行,每行有一个整数Ti 代表赵国部队的兵力. (1<=Ti<=1000) i=1,…N
输出
对于每一行测试数据,输出占一行,仅一个整数S,表示作战安排的最大战斗力.
样例输入
254
样例输出
64

感悟:
第一次见到这个题的时候,就有一种感觉,感觉会有规律,但是当时c语言一点毛皮都不会(大约三个月之前),出于对难题的恐惧,没敢继续想下去,就先放在那没做...
今天闲着没事的时候突然又见到了这个题,就感觉做做试试看吧,然后一推,发现可能就是这个规律(什么规律?别心急...慢慢看),只是比较复杂了而已,结合最近学的东西
,就试着做了做,没想到竟然对了!!!

自己总结的规律,不知道有没有相关理论证明,但是做这个题不错,说明应该是没问题的,但是在网上找不到相关资料证明,不知道为啥...........................

题意:

这个题,坦白了说就是给你若干个数(正整数)的和,让你求他们的乘积的最大值......

分析:
下面就是大脑运转,开始想了0.0........
以下只谈论整数.....
学过均值不等式,那时候求的是两个数和一定,求最大乘积,有这样一种极限模式,当两个数相等的时候就会有奇迹发生.....取到最大值了,如果和为奇数,那么就是分成两个相差一的数,别问为什么,自己想想看...
但是现在咱们是多个数,而且不清楚到底有多少数,但是别忘了,他们的和我们知道,假设是 S ,我们现在按刚才的想法想,那就相当于S是偶数的话,分成开两个 s / 2,应该是很大的,至于是不是最大,等会讨论,那就是相当于分成如果是 n 个数,那就是每个数都是 s / n 当然 s / n 不一定是整数,也就是最接近这个数的,这样的情况应该很特殊!!虽然咱们不知道是不是最大,然后继续讨论另一个问题....
如果一个数可以分成若干个某个数的乘积,那么哪个最大呢,这个就很有意思了,相当于 x 的 y 和y 的 x 次方哪个大的问题!!!
学过指数函数的都知道,指数的增长率非常大,也就是底数尽量小,让指数尽量大....
讨论一个特殊情况:有这些数的时候,4,8,16,32,......  或者 3,9,27,......5,25,125,.....7,49,243........
也就是可以拆成某个质数(合数可以用质数取代)的多少次方(假设可以)的时候,这是写非常特殊的情况,有可能取得最大!!
然后就是看这些质数哪些更大了,对比发现(指数函数的增长规律),底数为 3 的,可以取得最大的值!!!(其次是2,5,7.....)也就是 3的n 次方,不小于 x 的 y 次方,其中 x + y = n + 3 ,看不明白那就自己画画图,然后找几组数来验证吧........
 推导了半天,就是想说,优先考虑分成 3 的情况,然后最后考虑分成 2 的情况,注意最后不要分到剩下 1 ,这样浪费了,然后这就是规律,应该不会有问题的,下面就是写程序的问题了..............
感觉推规律的过程很复杂吧?但是程序也是很复杂的,因为按这个规律,在测试数据为1000的时候,这个求得的值就非常大了,至于有多大,我也不清楚.....
不过确定会超出64位,但是会小于300位.......嘿嘿,也就是大数思想了,下面就是用数组来模拟大数了...........
大数处理,个人喜欢模拟一万进位的,这样比平常的10进位的预计快了至少4倍,嘿嘿,而且个人还喜欢标记最高位,感觉这样比很多人那种直接从数组的最高位遍历,用循环去掉前导零的方法好多了,起码有技术含量啊.....汗....什么人这是....

讲解完毕,代码贴上..................

#include<stdio.h>
#include<string.h>
int t,x,i,len;
int y[105];
void mul(int n)//模拟大数乘法
{
	int c=0;
	for(i=0;i<len;++i)
	{
		y[i]=y[i]*n+c;
		c=0;
		if(y[i]>=10000)//考虑进位
		{
			c=y[i]/10000;
			y[i]%=10000;
		}
	}
	if(c)//讨论最高位
	{
		y[len]=c;
		++len;
	}
}
int main()
{
	scanf("%d",&t);
	while(t--)
	{
		memset(y,0,sizeof(y));//每次运算都别忘清零哦~
		y[0]=1;len=1;
		scanf("%d",&x);
		while(x>=2)//小于等于2,才可以继续分解...
		{
			if(x-3>1||x-3==0)//这两个分支就是模拟刚才的规则.....
			{
				mul(3);//调用
				x-=3;
			}
			else
			{
				mul(2);
				x-=2;
			}
		}
		printf("%d",y[--len]);//输出最高位
		for(i=len-1;i>=0;--i)
		{
			printf("%04d",y[i]);
		}
		printf("\n");
	}
	return 0;
} 




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值