1334C.Circles of Monsters(循环前缀和)

题意:

你在玩另一个电脑游戏,现在你必须杀死n个怪物。这些怪物站成一个圈,顺时针从1到n编号。最初,第i个怪物有ai生命值。

你可以射击怪物杀死他们。每次射击只需要一颗子弹,并且使目标怪物的生命值降低1(对其造成1点伤害)。此外,当某个怪物i的生命值变为0或小于0时,它会死亡并爆炸,对下一个怪物造成bi伤害(如果i如果下一个怪物已经死了,那么什么也不会发生。如果爆炸杀死了下一个怪物,它也会爆炸,在爆炸后破坏怪物并可能引发另一个爆炸,等等。

你必须计算你必须发射的子弹的最小数量,以杀死所有的n个怪物在圆。

输入

第一行包含一个整数T(1≤T≤150000)——测试用例的数量。

然后是测试用例,每个测试用例以一个整数n(2≤n≤300000)开始——怪物的数量。然后是n行,每一行包含两个整数ai和bi(1≤ai,bi≤1012)——圆中第i个怪物的参数。

保证所有测试用例中的怪物总数不超过300000。

输出

对于每个测试用例,打印一个整数——杀死所有怪物所需发射的子弹的最小数量。

题解:

给出一圈怪兽,每个怪兽都有生命值和攻击力,当你击杀一个怪兽,这个怪兽会对下一个怪兽造成等于它攻击力的伤害,依次传递,当无法击杀怪兽或者碰到已经死亡的怪兽就停止。询问至少要消灭多少生命值的怪兽才能击杀所有怪兽。

做法是开一个两倍的数组模拟循环,然后开一个C数组,表示以每个怪兽为起点发动攻击,所消耗的子弹数量,可以推导状态转移方程:

if (a[i]<=b[i-1])
    c[i]=c[i-1];
else 
    c[i]=c[i-1]+a[i]-b[i-1];
if (i>=N)
    ans=min(ans,c[i]-c[i-N+1]+a[i-N+1]);

完整代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=6e5+100;
typedef long long ll; 
ll a[maxn],b[maxn],c[maxn];
int main () {
    int T;
    scanf("%d",&T);
    while (T--) {
        int N;
        scanf("%d",&N);
        ll ans=1e18;
        for (int i=1;i<=N;i++) {
            scanf("%lld%lld",&a[i],&b[i]);
            a[N+i]=a[i];
            b[N+i]=b[i];
        }
        c[1]=0;
        for (int i=2;i<2*N;i++) {
            if (a[i]<=b[i-1])
                c[i]=c[i-1];
            else 
                c[i]=c[i-1]+a[i]-b[i-1];
            if (i>=N)
                ans=min(ans,c[i]-c[i-N+1]+a[i-N+1]);
        } 
        printf("%lld
",ans);
    }
}
原文地址:https://www.cnblogs.com/zhanglichen/p/12687404.html