zoukankan      html  css  js  c++  java
  • Codeforces 1334C


    两种思路其实只差在写法上

    看不懂的就直接看代码吧qwq


    UPD:

    注意题目给定的数据范围(Hack掉了很多)

    n最大3e5,a b最大1e12

    考虑最坏情况,即a=1e12,b=1,n=3e5

    最终答案为(1e12-1)*3e5+1略小于1e17

    所以无穷大值INF最好取大于1e17的值,下面的代码中LINF约为4.5e18




    题面

    Que




    题意

    n只怪物围成一圈,每只怪物拥有体力a和爆炸伤害b

    如果怪物 i 死亡(体力小于等于0),则与他相邻的下一只怪物将受到 b[i] 点伤害

    (如果 i<n ,则下一只怪物为 i+1 ;如果 i==n,则下一只怪物为 1)

    如果相邻的下一只怪物不存在,则什么也不会发生

    如果相邻的下一只怪物受到伤害后也死亡了,那么再下一只怪物会继续受到伤害(链式反应)

    每次你能随便挑一只怪物开一枪,那只怪物的体力将会降低 1 点

    问至少需要开多少枪才能解决掉所有怪物




    解题思路 1

    可以知道,只要挑出一只怪物作为最开始杀的那只,那接下来n-1只就按顺序杀下来就可以了

    所以问题最主要的就是找出最开始的这一只怪物

    又因为 n 最大有 3e5,每一次模拟都是O(n)的复杂度,总体时间复杂度O(n^2^)是绝对不可行的

    想了一个多小时才想到 于是发现可以用循环数组存前缀和来模拟出所有情况的答案

    但循环数组写起来太麻烦了,干脆直接开两倍长度的数组(3个6e5的long long不需要担心MLE)

    读入数据存在ar和br两个数组中

    并且让ar[i] == ar[i+n] && br[i] == br[i+n] ,i=1~n

    再开一个 used 数组,used[i] 记录从编号为 1 的怪物杀到编号为 i 怪物的过程中需要用掉多少颗子弹

    注意used只记录过程中,不记录杀编号为 1 的怪物用掉的子弹,处理过程如下:

      used[1] = 0 特殊处理

      i 从2开始,如果第 i 个怪物体力小于等于第 i-1 个怪物的爆炸伤害,说明只要前一只怪物死亡那这一只也会跟着死亡,对答案无贡献 used[i] = used[i-1]

      如果第 i 个怪物体力大于第 i-1 个怪物的爆炸伤害,说明还需要补上 ar[i] - br[i-1] 颗子弹才会死亡 used[i] = used[i-1] + ar[i] - br[i-1]

    因为原本是个循环数组,所以used需要处理到2*n过(实际上只要2*n-1)

    全部处理完后,那么所有情况就出来了

    比如说我们选择以 i=1 的怪物作为开始

    那么首先花费 ar[1] 颗子弹把这只怪物杀死

    然后从第1只开始杀n只,最后一只怪物的编号为 i=n

    所以过程中还需要多花费 used[n] - used[1] 颗子弹

    所以这种情况的答案就是 ar[1] + used[n] - used[1]

    推广,对于 i∈[1,n] 的每种情况,答案为 ar[i] + used[i+n-1] - used[i]

    取小输出即可




    程序 1

    把处理used数组的步骤和计算答案的步骤合起来

    则处理答案的范围为 n~2*n-1

    (280ms/1000ms)

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const ll LINF=0x3f3f3f3f3f3f3f3f;
    
    ll ar[600050],br[600050],used[600050];
    void solve()
    {
        int n;
        cin>>n;
        ll ans=LINF;
        for(int i=1;i<=n;i++)
        {
            cin>>ar[i]>>br[i];
            ar[n+i]=ar[i];
            br[n+i]=br[i];
        }
        used[1]=0;
        for(int i=2;i<2*n;i++)
        {
            if(ar[i]<=br[i-1])
                used[i]=used[i-1];
            else
                used[i]=used[i-1]+ar[i]-br[i-1];
            if(i>=n)
                ans=min(ans,used[i]-used[i-n+1]+ar[i-n+1]);
        }
        cout<<ans<<'
    ';
    }
    int main()
    {
        ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
        int T;cin>>T;
        for(int t=1;t<=T;t++)
            solve();
        return 0;
    }
    



    解题思路 2

    可以发现,思路1中的used[i+n] - used[i]其实是一个定值(注意不是 i+n-1 和 i )

    这个定值表示的就是忽略杀掉第一只怪物的花费,在过程中总共需要花费的子弹数

    令这个定值为 k ,k的求法即为k = k + sum{max(0,ar[i]-br[i-1])}

    有了这个定值,我们只需要找出杀第一只怪物最少的花费与其相加就是答案了

    令杀第一只怪物最少的花费为 minn

    与思路1的式子联立答案方程能得到

    used[i+n] - used[i] + minn == used[i+n-1] - used[i] + ar[i]

    ar[i] - minn == used[i+n] - used[i+n-1] == used[i] - used[i-1]

    所以可以知道 ar[i] 与 minn 的差值就在于 used[i] - used[i-1] 这一步

    而这个差值也就代表着某一步需要多消耗的子弹数

    得到minn == ar[i] - (used[i] - used[i-1])

    对于第 i 只怪物:

    如果br[i-1] >= ar[i]

      说明前一只死亡后会顺带让第 i 只怪物死亡

      所以在 k 的计算过程中并没有把杀死第 i 只怪物的花费记录进去

      即代表此时的used[i] - used[i-1] == 0

      所以此时可以得到 minn = min(minn,ar[i])

    如果br[i-1] < ar[i]

      说明前一只死亡后并不会顺带让第 i 只怪物死亡

      所以在 k 的计算过程中会加入 ar[i] 和 br[i-1] 的差值作为需要补的子弹数

      即代表此时的used[i] - used[i-1] == ar[i] - br[i-1]

      所以此时可以得到 minn = min(minn,br[i-1])

    最后再判断下编号为1和编号为n的这两只的关系




    程序 2

    (280ms/1000ms)

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const ll LINF=0x3f3f3f3f3f3f3f3f;
    
    ll ar[300050],br[300050];
    void solve()
    {
        int n;
        ll k=0,minn=LINF,d;
        cin>>n;
        for(int i=0;i<n;i++)
        {
            cin>>ar[i]>>br[i];
            d=ar[i]-br[i-1];
            if(i)
            {
                if(d>0)
                    minn=min(minn,br[i-1]),k+=d;
                else
                    minn=min(minn,ar[i]);
            }
        }
        d=ar[0]-br[n-1];
        if(d>0)
            minn=min(minn,br[n-1]),k+=d;
        else
            minn=min(minn,ar[0]);
        cout<<k+minn<<'
    ';
    }
    int main()
    {
        ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
        int T;cin>>T;
        for(int t=1;t<=T;t++)
            solve();
        return 0;
    }
    

  • 相关阅读:
    Power BI
    Power BI
    gulp的常用api
    关于promise
    webapp思路和rem适配极其viewport
    react初识
    node基础再现--module.exports 和exports
    sublime的js调试环境(基于node环境)
    题解 poj2778 DNA Sequence
    题解 TJOI/HEOI2016 字符串
  • 原文地址:https://www.cnblogs.com/stelayuri/p/12677416.html
Copyright © 2011-2022 走看看