• 博客园logo
  • 会员
  • 周边
  • 新闻
  • 博问
  • 闪存
  • 众包
  • 赞助商
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

yongchaoD

  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

打怪兽(模拟排序,暑假集训训练赛)

题目来源:https://codeforces.com/problemset/problem/1763/B
//
题意:n个怪兽,每个怪兽都有自己的生命值,攻击力属性,作为奥特曼,初始有自己的伤害值k,每次对每个怪兽攻击k点伤害后,奥特曼的伤害值会削弱,还存活的怪兽种的最小攻击力。问奥特曼是否能杀死所有的怪兽?
//
思路:“这个sb题啊,模拟的时候,就是有一个地方,时间复杂度会很高,就是某些怪兽死亡后,怎么又重新去维护存活的怪兽的最小攻击力,当时每次打一次怪兽后,都去遍历一边哪些怪兽死亡了,然后又sort一次,tle。然后又优化,判断最小攻击力的怪兽是否死了,死了再重sort,否则不管,其中这个地方离正解也不远了。”难点就是怎么去更新死掉的怪兽的攻击力。其中,我们只关心攻击力最小的怪兽死没死,是不是?所以对攻击力sort一次后,每次更新削弱伤害值,改成会造成伤害的总伤害值,只先看攻击力最小的怪兽死没,死了再后移一个就行了,最后直到伤害值加不了了。此时能造成怪兽的总伤害值也记录好了,但是后面存在攻击力很大,但是生命值很小的怪兽,没有来得及杀,所以要重新遍历一次,重杀一边。
//
题解:

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2e5 + 10;
const int mod = 1e9 + 7;
#define pii pair<int, int>

int n, k, h[N], p[N];
struct node
{
    int h, p;
    bool operator<(const node x) const
    {
        return p < x.p;//攻击力排序
    }
} a[N];
void solve()
{
    cin >> n >> k;
    for (int i = 1; i <= n; i++)
        cin >> a[i].h;
    for (int j = 1; j <= n; j++)
        cin >> a[j].p;
    sort(a + 1, a + n + 1);
    int cnt = 0, u = 1; // cnt为当前总的攻击值,u为当前p最小的怪兽下标
    while (k > 0)
    {
        cnt += k;//总伤害
        int mn = 1e9;
        while (u <= n && a[u].h - cnt <= 0) // h值已经小于0,看攻击力最小的你杀不杀得死,死就u++,一直杀,杀到攻击力削弱到0,就杀不动了
            u++;
        if (u == n + 1) // 所有的怪兽的h都小于了0,都杀完了
        {
            puts("YES");
            return;
        }
        mn = a[u].p;
        k -= mn;
    }
    for (int i = 1; i <= n; i++)//存在攻击力小的血厚实,后面攻击力大的血薄的,没杀到,重杀
    {
        if (a[i].h - cnt > 0) // 当有怪兽杀不死
        {
            puts("NO");
            return;
        }
    }
    puts("YES");
}

signed main()
{
    ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
    int T;
    cin >> T;
    while (T--)
        solve();
}
// 这里还有个用双set用法,开两个set,分别对生命值和攻击力排序,每次看能杀多少个怪兽,杀一个,记录死亡怪兽的生命值和攻击力,然后再用攻击力排序的set里面删除掉,为什么能再攻击力排序的set中精准找到死亡的怪兽,因为set开的是pair,知道了生命值和攻击力属性,当然就能find到了。 // // 题解2:
点击查看代码
#include<iostream>
#include<cmath>
#include<map>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<algorithm>
#include<cctype>
#include<cstring>
#include<list>
#define int long long
using namespace std;
const int N = 5e5+10;
int mod;
bool f = false;
int h[N], p[N];
set<pair<int,int> >a, b;
int n, m, x, y, le, ri, ans, num, max1, min1 = 0x3f3f3f3f;
void solve() {
    a.clear();
    b.clear();
    cin >> n >> m;
    for (int i = 0; i < n; i++) {
        cin >>h[i];//生命值
    }
    for (int i = 0; i < n; i++) {
        cin >> p[i];//攻击力
        a.insert({ h[i],p[i] });//用生命值进行排序
        b.insert({ p[i],h[i] });//攻击力排序
    }
    x = 0;
    while (!a.empty()&&m>0){
        x += m;//总攻击力
        while (!a.empty() && (*a.begin()).first <= x){//死亡
            int xue = (*a.begin()).first;//死亡的血量
            int gongji = (*a.begin()).second;//死亡的攻击力
            a.erase(a.begin());//删除死亡的
            b.erase(b.find({ gongji,xue }));//同时删除死亡的攻击力,通过死亡的xue和攻击力查找
        }
        m -= (*b.begin()).first;
    }
    if (a.empty())
        cout << "YES" << endl;
    else
        cout << "NO" << endl;
    return;
}
signed main() {
    int _ = 1;
    cin >> _;
    while (_--) {
        solve();
    }
    return 0;
}

posted on 2024-08-20 09:35  yongchaoD  阅读(32)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2026
浙公网安备 33010602011771号 浙ICP备2021040463号-3