hihocoder-1574-元素魔法--数学

hihocoder-1574-元素魔法--数学

题目1 : 元素魔法

时间限制:10000ms
单点时限:1000ms
内存限制:256MB

描述

小Hi是一个大魔法师,会用好多好多的魔法。小Hi一直在追求最强的魔法,每天都不敢懈怠,因此,小Hi今天也在勤勉地练习着魔法。

小Hi使用的魔法都是伤害类型的魔法,每次使用魔法时,小Hi会使用一定量的魔力,将这些魔力转化为不同类型的元素,再将这些元素组合起来释放。

小Hi的魔法的威力和他使用的元素的比例有关,假设小Hi能操纵的元素种类为k种,第i种元素的伤害系数为wi,某次魔法使用了xi单位的第i种元素,则该次魔法的威力为 ∏xiwi (其中xi和wi都是正的实数)。

小Hi的魔力是有限的,假设某天小Hi拥有的魔力为a(a也是正实数)魔法单位,则当天他最多能转换出总量为a单位的元素,即Σxi = a0 ≤ a。

每天他的魔力会随着使用魔法而消耗,只有在午夜0点才能回复。

由于小Hi对魔法的威力有着可怕的偏执,所以他每天只会使用一次魔法,并且这一次魔法的威力一定是他当天可能用出的所有魔法中,威力最大的一种。

但是小Hi不是很擅长数学,他希望有人帮他算出某天的魔法练习中他能释放出的魔法的最大威力是多少。

输入

第一行是一个正整数k(1 ≤ k ≤ 105),表示小Hi能操纵的元素种数。

第二行是1个正实数a(0 < a ≤  2 × 105),表示小Hi某天的魔力总量。

第三行是k个正实数,第i个正实数wi(1 < wi < 2)表示第i种元素的伤害系数。

所有输入的实数保证都精确到小数点后第四位。

输出

输出共两行。

第一行输出一个正实数,表示小Hi当天所能使出的威力最大的魔法的威力是多少,由于这个值可能很大也可能很小,请输出其对e(自然对数的底)取对数之后的结果。

第二行输出k个正实数,第i个正实数xi表示这个魔法中由xi单位的第i种元素混合而成,相邻的实数之间由空格隔开。

以上输出均四舍五入到小数点后第五位。

样例输入
5
56.2
1.7751 1.2748 1.5646 1.5052 1.7651
样例输出
19.13257
12.65227 9.08631 11.15190 10.72852 12.58099

 

题目这么长,总结一点就是求约束优化问题。

 max f = ln (x1^W1)*(x2^W2)* .... *(Xn^Wn) 

   = w1 * ln(x1) + w2*ln(x2) + ... + Wn * ln(Xn) 

   s.t. x1 + x2 + x3 + ... + Xn = a 

其中 a 和 Wi 已知, 

 

根据拉格朗日乘子法,可以得到下面的约束条件:

    x1 + x2 + .. + Xn - a = 0; 

    Wi / Xi + M = 0; 

那么,可以知道每一个 Wi 与 Xi 是成固定比例的。 所以知道这个结论,O(N) 时间内解决

 

#include <cstdio> 
#include <cmath> 
const int MAXN = 100000 + 10; 

int K; 
double a, num[MAXN], val[MAXN]; 

int main(){
	freopen("in.txt", "r", stdin); 

	while(scanf("%d", &K) != EOF){
		scanf("%lf", &a); 
		double sm = 0; 
		for(int i=0; i<K; ++i){
			scanf("%lf", &num[i]); 
			sm += num[i]; 
		}
		double idx = sm / a, ans = 0.0; 

		for(int i=0; i<K; ++i){
			val[i] = num[i] / idx; 
			ans += num[i] * log(val[i]); 
		}
		printf("%.5lf\n", ans );

		for(int i=0; i<K - 1; ++i){
			printf("%.5lf ", val[i] );
		}
		printf("%.5lf\n", val[K-1] );
	}
}

  

 

posted @ 2017-09-17 14:57  zhang--yd  阅读(235)  评论(0编辑  收藏  举报