P7725 珍珠帝王蟹 (Crab King) 题解
简要题意:
给定 \(n\) 个形如 \(+v\) 或 \(\times v\) 的操作以及初始数 \(0\),问怎样安排操作顺序能使最后的结果最大,输出其对 \(998244353\) 取模的结果。
数据范围:\(n\leq 10^5,2\leq \left|v\right|\leq 10^6\)
Subtask 1
\(O(n!)\) 枚举操作顺序,暴力判断最大值即可,注意到最大值不会超过 \(5^9=1953125\),所以不必考虑溢出。
Subtask 2
对于 \(v>0\) 的情况,假设我们已经得到了一个中间值 \(w\),考虑两个操作 \(+m\) 和 \(\times n\),怎样安排顺序才能最大化结果?
先加再乘:\((w+m)n=wn+mn\)
先乘再加:\(wn+m\)
显然先加、再乘是优于先乘、再加的。
所以总体的操作顺序就是先加、再乘正数。
Subtask 3
对于所有乘法操作保证 \(v>0\),即在 Subtask 2 的基础上多出了减法操作。
那么如何让减法对最后的结果影响最小?
首先,乘法要放在加法之后,才能保证其结果更优。
其次,减法不能在乘法或加法之前,不然会让乘法增大减法对答案的影响。
所以先加、再乘正数、最后减是最优方案。
Subtask 4
对于所有加法操作保证 \(v>0\),即在 Subtask 2 的基础上多出了乘负数的操作。
不会真有人还不知道负负得正吧。
如果乘负数的操作有偶数个,就和 Subtask 2 类似,只需要先加、再乘负数和正数即可。
那如果乘负数的操作有奇数个呢?
样例 \(1\) 的说明提示我们,可以在第一次操作前,把 \(0\) 乘上一个负数,这样就相当于让这个操作 “凭空消失” ,剩下的就和上面一致了。
Subtask 5
其实和上面的分析类似,我们需要考虑的就是如何让减法和乘负数对结果的影响最小 (或者说是对结果的贡献最大) 。
但是乘负数的操作数的奇偶性也会对顺序有影响。
所以按乘负数的操作数的奇偶进行分类。
- 乘负数的操作数是奇数。
不妨设有 \(2k+1\) 个操作。
对于减法操作来说,只需要让它们之和乘奇数个负数就能变成正数。
最优解是先减、再乘负数、再加、最后乘正数?显然还有更优的做法。
对于乘 \(2k\) 个较小的负数而言,他们是可以当作乘 \(2k\) 个较大的正数,而剩下的一个最大的负数就已经可以把减出来的负数变为正数了。
所以最优解应该是先减、再乘最大的负数、再加、最后乘剩下的负数和正数。
- 乘负数的操作数是偶数。
实话实说,比赛时这种情况卡了我很久。
一开始想的是跟奇数类似,再加上 Subtask 4 中先乘最大的负数的操作,也就是:
先乘最大的负数、再减、再乘第二大的负数、再加、再乘剩下的负数和正数。
但是提交之后发现这并不是正解。
思考一下:为什么我们在上一种情况中要把负数变成正数后再计算?
- \(2k\) 个乘负数的操作能乘出一个正数,但是我们有 \(2k+1\) 个。
- 而且这多出来的一个操作刚好能让减出来的负数变成正数。
那我们现在有 \(2k\) 个操作,是不是也可以让他多出来一个呢?
相信大家看到这里都能基本理解我的意思了,这里的操作与上一种情况基本相反。
既然我们想要剩下 \(2k-1\) 个乘负数的操作,我们就要让之前的所有操作得到的结果变成一个最小的负数。
所以最优解实际上是先加、再乘最大的负数、再减 (这里得到了最小的负数) 、最后乘剩下的负数和正数。
然而现在就对了吗?
对于 Subtask 3 (没有乘负数操作) 的情况,它的操作数确实是偶数,但我们得不到想要的最小负数,所以实际上这个做法只适用于操作数 \(\geq 2\) 的情况,对于操作数 \(=0\) 的情况,只需要特判并采用 Subtask 3 的做法即可。