LGP8365 [LNTS 2022] 吃 学习笔记

LGP8365 [LNTS 2022] 吃 学习笔记

Luogu Link

题意简述

\(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;
}
posted @ 2025-07-25 10:38  矞龙OrinLoong  阅读(4)  评论(0)    收藏  举报