LGP8365 [LNTS 2022] 吃 学习笔记
LGP8365 [LNTS 2022] 吃 学习笔记
题意简述
有 \(n\) 个数对 \((a_i,b_i)\)。你可以任意排列这 \(n\) 个数对,然后对你的初始为 \(1\) 的变量 \(v\) 进行如下操作:按顺序对于每个数对,选择将 \(v\) 乘上 \(a\) 或加上 \(b\)。最大化这个变量。输出时对 \(10^9+7\) 取模。
\(n\le 5\times 10^5\),\(1\le a_i,b_i\le 10^6\)。
做法解析
首先 \(a_i,b_i\) 都是正数所以不会出现什么负收益,没有了很多麻烦的讨论。
然后呢?首先我们知道如果 \(a_i=1\) 那肯定选择加 \(b_i\)(因为乘 \(1\) 没有任何收益),其次所有加操作肯定都要放到乘操作前面。
最关键的性质是,对于 \(a_i\neq 1\) 的 \(i\),最多存在一个选择加。因为无论如何两个加一定劣于一个加一个乘。
那么我们就可以枚举要不要另选择哪个 \(i\) 使用加法。具体来说,我们定义“初始方案”的答案为 \(V=(\sum_{a_i=1}b_i)\times(\prod_{a_i\neq 1}a_i)\)。那么当我们将一个 \(a_i\neq 1\) 的 \(i\) 改选加 \(b_i\) 时,相当于最终答案就是 \(V\) 乘上了 \(\frac{S+b_i}{a_i}\) 的系数。我们最大化这个系数即可。
代码实现
#include <bits/stdc++.h>
using namespace std;
using namespace obasic;
const int MaxN=5e5+5;
int N,flg[MaxN];
struct anob{lolo x,y;}D[MaxN];
lolo psum;
int main(){
readi(N);psum=1;
for(int i=1;i<=N;i++)readi(D[i].x);
for(int i=1;i<=N;i++)readi(D[i].y);
for(int i=1;i<=N;i++)if(D[i].x==1)psum+=D[i].y,flg[i]=1;
doub fsum=psum;int mc=0;
for(int i=1;i<=N;i++){
if(flg[i])continue;
doub csum=1.0*(psum+D[i].y)/D[i].x;
if(csum>fsum)fsum=csum,mc=i;
}
if(mc)(psum+=D[mc].y)%=M107,flg[mc]=1;
for(int i=1;i<=N;i++)if(!flg[i])(psum*=D[i].x)%=M107;
writi(psum);
return 0;
}
浙公网安备 33010602011771号