(JZ4245)2019.01.29【NOIP提高组】模拟B组 1.er(混沌与秩序)

【五校联考6day2】er

Description

小明在业余时间喜欢打电子游戏,不是星际和魔兽这些,是赛尔号一类的游戏。最近小明在玩一款新出的游戏,叫做■■■■■■■■。小明觉得游戏里自己的装备太垃圾了,每次都被大神虐,一怒之下充了■■元准备强化装备。
这个游戏中用于强化装备的道具叫做强化符文。有以下3 种:

  1. 赋值强化符文,对某个装备使用这个符文以后,装备威力值会变为一个常数。因为这个功能很IMBA,可以让一个垃圾装备变得非常牛■,所以它在游戏里很稀有,市场上最多能见到一个。
  2. 加法强化符文,对某个装备使用后,威力值加上一个常数。
  3. 乘法强化符文,对某个装备使用后,威力值乘上一个常数。
    市场上有M 个不同强化符文可以购买,小明有N 件装备准备强化,他只能购买K 个强化符文,然后以任意顺序使用这些符文,强化他的任意装备(一个装备可以不强化也可以强化多次)。根据游戏的设定,所有装备威力值乘积为总效果。请为他设计一个购买和强化方案,使强化后的所有装备总效果值最大。
    由于小明RP 不太好,打BOSS 都不掉神装,所以他的装备不超过两件。

Input

第一行3 个正整数N;M;K, 含义见题面。
第二行N 个正整数Ai,表示他的每个装备的初始威力值。
第三行开始共M 行,每行两个正整数Type_i;Ci,描述一个强化符文。Type_i表示符文类型,1 表示赋值,2 表示加法,3 表示乘法。Ci 是对应的常数值。

Output

一个数,表示最大的总效果值。由于这个数可能很大,请输出它的自然对数,保留3 位小数。

Sample Input
2 5 3
0 1
2 3
2 1
2 4
3 4
3 2

Sample Output
4.159

Data Constraint

对于20% 的数据,N = 1;
对于全部数据M,K ≤ 100;N ≤ 2,最多一个Type_i = 1。
输入数据中所有数不超过2000。

纪中题解:

首先,因为赋值强化符文最多只有一个,可以枚举它用不用,至多算 3 次。相当于没有这个东西。
先考虑 N = 1 的情况。如果已知选几个加法符文几个乘法符文,那么一定是选数值最高的,一定是先加后乘,也就是说,决定了选择的两种符文的数量就可以确定最后的结果。所以可以先排好序,计算前缀和,枚举选几个加法符文,就可以计算出当前的总数值,用它来更新答案。复杂度 O(M)
N = 2 的情况,乘法符文没什么区别,因为最后算答案的时候是两个装备数值相乘,随便乘哪里都没关系。但是加法符文就不同了,决定了选几个加法符文还不够,还要考虑该怎么分配到两个装备上。直觉上暴力枚举复杂度好象是指数级的。但是我们只需考虑相加后的答案,如果给第一个装备分配的数值之和为 x,那么给第二个装备分配的数值也就确定了,而这个 x 最多只有2000 × 100 = 200000 种情况,比指数级小多了。具体在实现时,可以在枚举选几个加法符文的同时,用背包算法算出所有可能的分配情况并枚举这些情况计算答案。复杂度 O(M ×∑Ai)。

个人补充:(参考自andyscl的blog)

   分n=1,n=2两种情况讨论
   n=1时,排序后直接贪心加,之后直接乘;或者用前缀和也可以(但还是要排序哦)
   n=2时,枚举i,表示用了i个加法,那么再枚举一个j,j表示用<=i个加法的值给第一个数。然后就处理加法的前缀和 s u m [ i ] sum[i] sum[i]和乘法的前缀和 n u m [ i ] num[i] num[i]。知道另一个加了多少 s u m [ i ] − x s u m [ i ] − x sum[i]−xsum[i]−x sum[i]xsum[i]x,再用 ( s u m [ i ] − x + a ) ∗ ( x + b ) ∗ n u m [ k − i ] ( s u m [ i ] − x + a ) ∗ ( x + b ) ∗ n u m [ k − i ] (sum[i]−x+a)∗(x+b)∗num[k−i](sum[i]−x+a)∗(x+b)∗num[k−i] sum[i]x+a(x+b)num[ki]sum[i]x+a(x+b)num[ki]比较答案。处理j是否可行就可以用背包判定。

story↗ time↘(请脑补卡面来打gaizgay子的音效):

   一开始,觉得:只用先赋值更大的值给小的装备,再加威力较小的装备,最后加起来再乘一下就完事了。
   然后,发现:所有装备威力值乘积为总效果。ok,那最后+便乘×不就行了吗?结果发现跑出来的是:5.075。再按照自己的思路看样列,算出来的是160,而ln(160)≈5.075。而题目的是ln(64)≈4.159。顿时黑人问号脸,只能代入数据,将第一个武器加上1,最后就是(0+1)*(1+3+4)*2 *3=64完工了!(๑′ᴗ‵๑)
   最后就爆蛋了…请看清楚k是什么:他只能购买K 个强化符文orz

#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
using namespace std;
int n,m,k,z,w,a[5],len1,len2;
long long cnt,sum[105],p[105],s[105],f[200005];
double ans,sec[105];

void bag(int x){
    for (int j=z; j>=x; j--) 
		f[j]=max(f[j],f[j-x]);
}

void single(){
    for (int i=0; i<=len1; i++){
    	if (i>k) break;
    	ans=max(ans,log(1.0*(sum[i]+a[1]))+sec[k-i]);
    	ans=max(ans,log(1.0*(w+sum[i]))+sec[k-i-1]);
	}
}

void doouble(){
	sec[0]=1;f[0]=1;
    for (int i=0; i<=len1; i++){
       	if (i>k) break;
       	bag(sum[i]-sum[i-1]);
       	if (k-i==len2) sum[0]=0;
        for (int j=0; j<=sum[i]; j++) 
        	if (f[j]>0&&f[sum[i]-j]>0) {
         		cnt=sum[i]-j;
         		ans=max(ans,log((cnt+a[1])*1.0)+log((j+a[2])*1.0)+sec[k-i]);
         		ans=max(ans,log((cnt+a[1])*1.0)+log((j+a[2]+w)*1.0)+sec[k-i-1]);
         		ans=max(ans,log((cnt+a[1]+w)*1.0)+log((j+a[2])*1.0)+sec[k-i-1]);
       		}
    }
}
int main (){
	scanf("%d%d%d",&n,&m,&k);
	for (int i=1; i<=n; i++) scanf("%d",&a[i]);
    for (int i=1; i<=m; i++){
    	int x,y;
		scanf("%d%d",&x,&y);
        if (x==1) w=y;
	   	 else if (x==2) p[++len1]=y; 
		   		   else s[++len2]=y;
    }
    sort(p+1,p+len1+1,greater<int>()); sum[0]=0;
	for (int i=1; i<=len1; i++) sum[i]=sum[i-1]+p[i]; z=sum[len1];
    sort(s+1,s+len2+1,greater<int>()); sec[0]=0;
	for (int i=1; i<=len2; i++) sec[i]=sec[i-1]+log(s[i]*1.0);
    if (n==1) single();
    	 else doouble();
    printf("%.3lf",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值