小明在业余时间喜欢打电子游戏,不是星际和魔兽这些,是赛尔号一类的游戏。最近小明在玩一款新出的游戏,叫做■■■■■■■■。小明觉得游戏里自己的装备太垃圾了,每次都被大神虐,一怒之下充了■■元准备强化装备。
这个游戏中用于强化装备的道具叫做强化符文。有以下3 种:
第一行3 个正整数N;M;K, 含义见题面。
第二行N 个正整数Ai,表示他的每个装备的初始威力值。
第三行开始共M 行,每行两个正整数Type_i;Ci,描述一个强化符文。Type_i表示符文类型,1 表示赋值,2 表示加法,3 表示乘法。Ci 是对应的常数值。
一个数,表示最大的总效果值。由于这个数可能很大,请输出它的自然对数,保留3 位小数。
Sample Input
2 5 3
0 1
2 3
2 1
2 4
3 4
3 2
Sample Output
4.159
对于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)。
分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[k−i](sum[i]−x+a)∗(x+b)∗num[k−i]比较答案。处理j是否可行就可以用背包判定。
一开始,觉得:只用先赋值更大的值给小的装备,再加威力较小的装备,最后加起来再乘一下就完事了。
然后,发现:所有装备威力值乘积为总效果。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
#include
#include
#include
#include
#include
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);
}