NOI模拟 大战波特

涉及知识点:贪心

前言

思维难度不高,就是挺好玩的,随手记录下有意思的贪心,奇妙的贪心经常比复杂的 DP 还有意思。

题意

打 Boss,总共可以打 \(n\ (\leq10^6)\) 回合,每回合可以普攻一次,造成 \(x\) 点伤害,每回合可以使用咒语,总共最多使用 \(k\) 次,使得 Boss 赋予一层“中毒”效果,并减弱一层“回复”效果(如果之前存在“回复”效果的话),Boss 每回合也可以使用咒语给自己赋予一层”回复“效果,注意同一回合可以同时普攻与使用咒语。“中毒”效果指每回合结束后 Boss 受到 \(p\) 点伤害,“回复”效果指每回合结束后 Boss 得到 \(r\) 点血量。不存在血量上限或下限,效果可叠加,已知 Boss 哪些回合使用 ”回复“ 咒语,求 \(n\) 回合后 Boss 最多掉了多少血(可能为负数)。

思路

阻碍我们贪心的最大问题在于要同时考虑减弱”回复“效果和造成持续伤害,因此我们可以尝试将”回复“效果直接量化为血量的变化。并且有贪心策略:如果我们想要减弱某一层”回复“效果,一定是直接就在该”回复“效果产生的回合使用咒语最优,”回复“效果产生后几回合才减弱它是一定不优的。

我们首先假设每回合 Boss 的”回复“都生效且没被减弱,如果回合 \(i\) 时 Boss 使用了咒语,那么我方使用咒语带来的总伤害为 \((p+r)(n-i+1)\)(要把”回复“那部分抵消),否则总伤害为 \(p(n-i+1)\),将每个回合使用咒语的预期伤害排序后选最大 \(k\) 个即可。并且使用或不使用咒语的伤害序列分别有单调性,最后可以使用归并排序做到严格线性。

FAQ:

有人可能会疑问为什么 Boss 不使用咒语时,我方使用咒语的伤害就只有 \(p(n-i+1)\)?因为可以证明贪心到这个时候时 Boss 一定是没有”回复“效果的:如果 \(i\) 前面有某个回合 \(j\) Boss 使用了咒语并且没有被减弱,那么我们直接在 \(j\) 使用咒语造成的伤害一定更高。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN=1e6+5;
LL n,x,r,p,k;
LL ans=0,atk[MAXN];
string opt;
int main(){
    // freopen("bot.in","r",stdin);
    // freopen("bot.out","w",stdout);
    cin>>n>>x>>r>>p>>k>>opt;
    for(int i=0;i<n;i++){
        ans+=x;
        if(opt[i]=='1'){
            ans-=r*(n-i);
            atk[i]=(p+r)*(n-i);
        }
        else{
            atk[i]=p*(n-i);
        }
    }
    sort(atk,atk+n,greater<LL>());
    for(int i=0;i<k;i++){
        ans+=atk[i];
    }
    cout<<ans<<endl;
    return 0;
}
posted @ 2024-05-09 23:07  MessageBoxA  阅读(5)  评论(0编辑  收藏  举报