Educational Codeforces Round 85 C. Circle of Monsters(贪心)
You are playing another computer game, and now you have to slay nn monsters. These monsters are standing in a circle, numbered clockwise from 11 to nn . Initially, the ii -th monster has aiai health.
You may shoot the monsters to kill them. Each shot requires exactly one bullet and decreases the health of the targeted monster by 11 (deals 11 damage to it). Furthermore, when the health of some monster ii becomes 00 or less than 00 , it dies and explodes, dealing bibi damage to the next monster (monster i+1i+1 , if i<ni<n , or monster 11 , if i=ni=n ). If the next monster is already dead, then nothing happens. If the explosion kills the next monster, it explodes too, damaging the monster after it and possibly triggering another explosion, and so on.
You have to calculate the minimum number of bullets you have to fire to kill all nn monsters in the circle.
The first line contains one integer TT (1≤T≤1500001≤T≤150000 ) — the number of test cases.
Then the test cases follow, each test case begins with a line containing one integer nn (2≤n≤3000002≤n≤300000 ) — the number of monsters. Then nn lines follow, each containing two integers aiai and bibi (1≤ai,bi≤10121≤ai,bi≤1012 ) — the parameters of the ii -th monster in the circle.
It is guaranteed that the total number of monsters in all test cases does not exceed 300000300000 .
For each test case, print one integer — the minimum number of bullets you have to fire to kill all of the monsters.
1 3 7 15 2 14 5 3
6
题意是n个怪排成一圈,每个怪有一定血量ai,其死亡会对它的位置+1处的怪产生bi的伤害(如果那里的怪死了就没影响了),一颗子弹可以减一滴血,问最少多少颗子弹能干掉所有的怪。
貌似有很多种思路,本质上都差不多。第一种是只需要确定一开始攻击的怪就行。因为把第一个怪打死后,最优策略为继续攻击被炸伤的怪,因为被炸伤的怪没法再被炸一次了,只能消耗子弹攻击它,而如果选择其他满血的怪打,那个怪本可以先被炸再打的,这样无疑浪费了子弹。因此只需要先处理出每个怪的血量减去爆炸所受伤害的前缀和,枚举一下一开始打哪个怪,答案取最小即可。注意成环的话要复制一遍数组。
另一种思路是先对每个怪攻击,直到其能被旁边的怪一发入魂,再枚举先要打死的怪,这样一连串直接爆掉。
#include <bits/stdc++.h> using namespace std; int n; struct mon { long long a; long long b; }m[300005]; long long sum[600005]; int main() { int t; cin>>t; while(t--) { scanf("%d",&n); int i; for(i=1;i<=n;i++)scanf("%lld%lld",&m[i].a,&m[i].b); for(i=1;i<=n;i++) { if(i==1)sum[1]=sum[n+1]=m[n].b>=m[1].a?0:m[1].a-m[n].b; else { sum[i]=sum[i+n]=m[i-1].b>=m[i].a?0:m[i].a-m[i-1].b; } } sum[0]=0; for(i=1;i<=2*n;i++) { sum[i]+=sum[i-1];//前缀和 } long long ans=1e18; for(i=1;i<=n;i++) { ans=min(ans,m[i].a+sum[i+n-1]-sum[i]); } printf("%lld\n",ans); } return 0; }