Strength(HDU6563+2018年吉林站+双指针瞎搞)

这是一篇关于计算策略问题的博客,通过双指针解决如何在两种状态下(普通和防守)最大化对对手怪的伤害。文章详细介绍了题意、思路以及具体的代码实现,重点在于利用双指针优化策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接

传送门

题意

你有 n n n只怪,每只怪的伤害为 a i a_i ai,对手有 m m m只怪,每只怪的伤害为 b i b_i bi,对手的怪有普通状态和防守状态(普通状态:如果你用攻击力为 a i ( a i ≥ b j ) a_i(a_i\geq b_j) ai(aibj)的怪去攻击对手第 j j j只怪将会给对手造成 a i − b j a_i-b_j aibj的伤害;防守状态则不会造成 a i − b j a_i-b_j aibj的伤害),每只怪只能使用一次,怪一旦死亡就会消失。
用攻击力为 x x x的怪去打攻击力为 y ( x ≤ y y(x\leq y y(xy x ≥ y x\geq y xy的情况上面说了 ) ) )的怪会有以下两种情况:

  • x &lt; y x&lt;y x<y:对手不受到任何伤害,自己的怪死亡;
  • x = y x=y x=y:对手不受到任何伤害,双方的怪死亡;

如果对手所有的怪都死亡了,那么你就可以直接攻击对手且伤害为你的怪的伤害值。
问你你能给对手造成的最大伤害值是多少。

思路

本题分两种情况进行考虑:

  • 全部的怪都去打对手普通状态的怪,注意这种情况下不能直接攻击对手
  • 将防守状态和普通状态的怪都打死,然后用剩余的怪去打对手。

我们知道用剩余怪中伤害值大的去打对手剩余怪中伤害值大的是最优解(如果用伤害值大的去打其他怪的话,到后面可能会导致有怪打不死对手伤害值高的怪),因此用两个双指针瞎搞就可以了。

代码实现如下

#include <set>
#include <map>
#include <deque>
#include <queue>
#include <stack>
#include <cmath>
#include <ctime>
#include <bitset>
#include <cstdio>
#include <string>
#include <vector>
#include <cstdlib>
#include <cstring>
#include <cassert>
#include <iostream>
#include <algorithm>
#include <unordered_map>
using namespace std;

typedef long long LL;
typedef pair<LL, LL> pLL;
typedef pair<LL, int> pLi;
typedef pair<int, LL> pil;;
typedef pair<int, int> pii;
typedef unsigned long long uLL;

#define lson rt<<1
#define rson rt<<1|1
#define lowbit(x) x&(-x)
#define name2str(name) (#name)
#define bug printf("*********\n")
#define debug(x) cout<<#x"=["<<x<<"]" <<endl
#define FIN freopen("D://Code//in.txt","r",stdin)
#define IO ios::sync_with_stdio(false),cin.tie(0)

const double eps = 1e-8;
const int mod = 1e9 + 7;
const int maxn = 1e5 + 7;
const double pi = acos(-1);
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3fLL;

int t, n, m;
vector<int> vec1, vec2;
int a[maxn], vis1[maxn], vis2[maxn];

struct node {
    int val, pos;
    bool operator < (const node& x) const {
        return val < x.val;
    }
}pp[maxn];

int main() {
#ifndef ONLINE_JUDGE
FIN;
#endif // ONLINE_JUDGE
    scanf("%d", &t);
    int icase = 0;
    while(t--) {
        scanf("%d%d", &n, &m);
        vec1.clear(), vec2.clear();
        for(int i = 1; i <= n; ++i) {
            scanf("%d", &a[i]);
            vis1[i] = 0;
        }
        sort(a + 1, a + n + 1);
        for(int i = 1; i <= m; ++i) {
            scanf("%d", &pp[i].val);
            vis2[i] = 0;
        }
        int num = 0, flag = 1;
        for(int i = 1; i <= m; ++i) {
            scanf("%d", &pp[i].pos);
            if(pp[i].pos) ++num, flag = 0;
        }
        sort(pp + 1, pp + m + 1);
        if(n > num) {
            for(int i = 1, j = 1; i <= n; ++i) {
                while(!pp[j].pos) ++j;
                if(j > m) break;
                if(a[i] >= pp[j].val) {
                    --num;
                    vis1[i] = vis2[j] = 1;
                    ++j;
                }
            }
        }
        for(int i = 1; i <= n; ++i) {
            if(vis1[i]) continue;
            vec1.emplace_back(a[i]);
        }
        for(int i = 1; i <= m; ++i) {
            if(vis2[i] || pp[i].pos) continue;
            vec2.emplace_back(pp[i].val);
        }
        LL ans1 = 0, ans2 = 0;
        for(int i = vec1.size() - 1, j = vec2.size() - 1; i >= 0; --i) {
            while(j >= 0 && vec1[i] < vec2[j]) --j;
            if(j < 0 && num == 0) {
                ans1 += vec1[i];
                continue;
            } else if(j < 0) continue;
            ans1 += vec1[i] - vec2[j];
            --j;
        }
        for(int i = n, j = m; i >= 0; --i) {
            while(j > 0 && (pp[j].pos || pp[j].val > a[i])) --j;
            if(j <= 0 && flag) {
                ans2 += a[i];
                continue;
            } else if(j <= 0) continue;
            ans2 += a[i] - pp[j].val;
            --j;
        }
        printf("Case %d: %lld\n", ++icase, max(ans1, ans2));
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值