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\n",ans); } }