题意
有 n n n个东西 ( n < = 2 ) (n<=2) (n<=2),我们有 k k k种符文可以改变某个东西的价值。
有三种符文形式如下:
1、赋值强化符文,直接把一个东西赋值为一个常数。
2、加法强化符文,把一个东西加上一个常数。
3、乘法强化符文,把一个东西乘上一个常数。
最多能用 k k k个符文,求出按某种顺序用某些符文后这 n n n个东西的乘积的自然对数最大。
思路
首先有
l
o
g
e
(
a
b
)
log_e(ab)
loge(ab)=
l
o
g
e
(
a
)
+
l
o
g
e
(
b
)
log_e(a)+log_e(b)
loge(a)+loge(b)。
证明:
不妨设
l
o
g
e
(
a
b
)
=
x
、
l
o
g
e
(
a
)
=
p
、
l
o
g
e
(
b
)
=
q
log_e(ab)=x、log_e(a)=p、log_e(b)=q
loge(ab)=x、loge(a)=p、loge(b)=q。
那么
e
x
=
a
b
、
e
p
=
a
、
e
q
=
b
e^x=ab、e^p=a、e^q=b
ex=ab、ep=a、eq=b
又因为
e
p
∗
e
q
=
a
b
、
e
p
+
q
=
a
b
e^p*e^q=ab、e^{p+q}=ab
ep∗eq=ab、ep+q=ab
所以
p
+
q
=
x
p+q=x
p+q=x。
根据这个,我们就可以分别计算加法和乘法的答案,至于赋值强化符文,我们可以暴力去判断。
n
=
1
n=1
n=1时,我们可以用随便搞搞,下面是
n
=
2
n=2
n=2的情况。
设
f
i
,
j
f_{i,j}
fi,j表示用前
i
i
i个加法强化符文,第一个东西的价值为
j
j
j的两个价值的最大乘积。
两种转移,表示加给第一个东西或加给第二个东西,我们用前缀和记录加法符文的和,然后就通过第一个东西求出第二个东西的值了。
最后枚举一下选乘法符文的情况,计算一下最大答案。
代码
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
int n, m, k, p1, p2, type1, lenAdd, lenMul;
int add[101], mul[101], sum[101], maxadd[101];
int f[101][200001];
double ans;
double sumMul[101];
int cmp(int x, int y) {
return x > y;
}
int main() {
scanf("%d %d %d", &n, &m, &k);
scanf("%d", &p1);
if (n == 2) scanf("%d", &p2);
for (int i = 1, op; i <= m; i++) {
scanf("%d", &op);
if (op == 1) scanf("%d", &type1);
else if (op == 2) scanf("%d", &add[++lenAdd]);
else scanf("%d", &mul[++lenMul]);
}
std::sort(add + 1, add + lenAdd + 1, cmp);
std::sort(mul + 1, mul + lenMul + 1, cmp);
sum[0] = p1 + p2;
for (int i = 1; i <= k; i++) {
sum[i] = sum[i - 1] + add[i];
sumMul[i] = sumMul[i - 1] + log(mul[i]);
}
if (n == 1) {
for (int i = 0; i <= k; i++) {
ans = std::max(ans, log(sum[std::min(i, lenAdd)]) + sumMul[std::min(k - i, lenMul)]);
if (i != k && type1)
ans = std::max(ans, log(type1 + sum[std::min(i, lenAdd)] - p1) + sumMul[std::min(k - i - 1, lenMul)]);
}
printf("%.3lf", ans);
return 0;
}
memset(f, 0xcf, sizeof(f));
f[0][p1] = p1 * p2;
for (int i = 0; i <= lenAdd; i++)
for (int j = p1; j <= sum[i] - p2; j++) {
f[i + 1][j + add[i + 1]] = std::max(f[i + 1][j + add[i + 1]], f[i][j] + add[i + 1] * (sum[i] - j));
f[i + 1][j] = std::max(f[i + 1][j], f[i][j] + add[i + 1] * j);
maxadd[i] = std::max(maxadd[i], f[i][j]);
}
for (int i = 0; i <= k; i++)
ans = std::max(ans, log(maxadd[std::min(lenAdd, i)]) + sumMul[std::min(k - i, lenMul)]);
if (type1) {
k--;
sum[0] = type1 + p2;
for (int i = 1; i <= k; i++)
sum[i] = sum[i - 1] + add[i];
memset(f, 0xcf, sizeof(f));
memset(maxadd, 0, sizeof(maxadd));
f[0][type1] = type1 * p2;
for (int i = 0; i <= k; i++)
for (int j = type1; j <= sum[i] - p2; j++) {
f[i + 1][j + add[i + 1]] = std::max(f[i + 1][j + add[i + 1]], f[i][j] + add[i + 1] * (sum[i] - j));
f[i + 1][j] = std::max(f[i + 1][j], f[i][j] + add[i + 1] * j);
maxadd[i] = std::max(maxadd[i], f[i][j]);
}
for (int i = 0; i <= k; i++)
ans = std::max(ans, log(maxadd[std::min(lenAdd, i)]) + sumMul[std::min(k - i, lenMul)]);
sum[0] = p1 + type1;
for (int i = 1; i <= k; i++)
sum[i] = sum[i - 1] + add[i];
memset(f, 0xcf, sizeof(f));
memset(maxadd, 0, sizeof(maxadd));
f[0][p1] = p1 * type1;
for (int i = 0; i <= k; i++)
for (int j = p1; j <= sum[i] - type1; j++) {
f[i + 1][j + add[i + 1]] = std::max(f[i + 1][j + add[i + 1]], f[i][j] + add[i + 1] * (sum[i] - j));
f[i + 1][j] = std::max(f[i + 1][j], f[i][j] + add[i + 1] * j);
maxadd[i] = std::max(maxadd[i], f[i][j]);
}
for (int i = 0; i <= k; i++)
ans = std::max(ans, log(maxadd[std::min(lenAdd, i)]) + sumMul[std::min(k - i, lenMul)]);
}
printf("%.3lf", ans);
}