• Codeforces 1257D


    题意

    (n)个怪物,每个怪物有攻击力(a_i)点;有(m)个英雄,每个英雄有攻击力(p_i)点,耐力(s_{i})点。

    怪物需要被依次杀死(按输入顺序)。

    每一天可以挑选一个英雄去杀怪物,他可以杀死的怪物攻击力小于等于他本身(即(aleq p)),每天最多可以杀死(s)个怪物。(每个英雄可以使用任意次)

    问最少需要多少天可以杀死所有怪物(不能则输出(-1))。

    分析

    ((1))我们找到怪物的最大攻击力和英雄的最大攻击力,判断是否要输出(-1)

    ((2))将英雄按攻击力(p)值排序,我们可以发现对于英雄(b[i])而言,如果对于(i<jleq m),且有(b[i].s<b[j].s),我们可以选择英雄(j),而不是英雄(i),那么我们可以把(b[i].s)替换为(b[j].s)(意思为选择英雄(i)时选择英雄(j))。

    ((3))因此我们进行后缀操作将(b[i].s)改为英雄(i)~(n)中最大的耐力值,以便进行下一步。

    ((4))对于某个怪物而言,我们可以找到一个英雄,他的攻击力刚好大于等于该怪物(二分)。我们上一步将该英雄的耐力改为了后缀最大值,那么我们便选择这个英雄。

    ((5))我们从第一天开始,枚举每一个怪物,找到当前天我们可以杀死最多怪物的英雄,如果对于某个怪物而言,杀死他的人的耐力(我们进行了后缀操作)不足以支撑该天,我们将该怪物放到下一天,并重复操作,直至杀死所有怪物。因此我们需要保存的量有:当前的天数(k),昨天杀死的最后一只怪物的编号(last),今天所能杀死的最多怪物数(表现为所需要的最小耐力)(minn)

    #pragma GCC optimize(3, "Ofast", "inline")
    
    #include <bits/stdc++.h>
    
    #define start ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    #define ll long long
    #define LL long long
    using namespace std;
    const int maxn = (ll) 2e5 + 5;
    const int mod = 1000000007;
    const int inf = 0x3f3f3f3f;
    
    struct node {
        int p, s;
    
        bool operator<(const node &b) {//用做排序
            return p < b.p;
        }
    } b[maxn];
    
    bool cmp(const node &x, int y) {//用做二分
        return x.p < y;
    }
    
    int a[maxn];
    
    int main() {
        start;
        int T;
        cin >> T;
        while (T--) {
            int n;
            cin >> n;
            int maxa = 0, maxs = 0;//用做判-1
            for (int i = 1; i <= n; ++i) {
                cin >> a[i];
                maxa = max(maxa, a[i]);
            }
            int m;
            cin >> m;
            for (int i = 1; i <= m; ++i) {
                cin >> b[i].p >> b[i].s;
                maxs = max(maxs, b[i].p);
            }
            if (maxa > maxs) {
                cout << -1 << '
    ';
                continue;
            }
            sort(b + 1, b + m + 1);
            for (int i = m - 1; i >= 1; --i)//后缀操作
                b[i].s = max(b[i].s, b[i + 1].s);
            int k = 1;
            int last = 0;
            int minn = inf;
            for (int i = 1; i <= n; ++i) {
                int t = lower_bound(b + 1, b + m + 1, a[i], cmp) - b;//刚好能杀死该怪物的英雄编号
                minn = min(b[t].s, minn);//今天所需要的最小耐力
                if (minn + last < i) {//将这只怪物放到明天杀
                    minn = b[t].s;
                    ++k;
                    last = i - 1;
                }
            }
            cout << k << '
    ';
        }
        return 0;
    }
    

    本场比赛(D)(E)惨痛教训:玩后缀一定要注意边界!!!

  • 相关阅读:
    SPSS时间序列:频谱分析
    PureBasic—数控编辑框与调节块和进度条
    DELPHI2007 安装ACTIVEX插件的方法
    C++ builder的文件操作
    C++动态数组
    excel快速复制大量公式的方法
    Delphi XE5 如何与其他版本共存
    PureBasic 集成Form设计器的使用
    VS C++ 从一个窗口创建另一个窗口
    ENVI 5.0 Beta 体验——影像数据的显示
  • 原文地址:https://www.cnblogs.com/F-Mu/p/11868374.html
Copyright © 2020-2023  润新知