题目:
Monocarp 正在玩电脑游戏(又一次)。猜猜他在做什么?没错,杀怪。
一排有 n个怪物,编号从 1 到 n 。其中 i号 个怪物有两个参数:攻击值等于 ai,防御值等于 di 。为了杀死这些怪物,莫诺卡普给它们施放了狂暴咒语,因此它们会互相攻击,而不是攻击莫诺卡普的角色。
战斗由 n个回合组成。每回合都会发生以下情况:
- 首先,每个 i活着的怪物都会对左边最近的活着的怪物(如果存在)和右边最近的活着的怪物(如果存在)造成 ai 伤害;
- 然后,每个在本回合中受到超过 dj 伤害的活着的怪物 j 死亡。也就是说,当且仅当 j 怪物的防御值 dj 严格小于它在本轮受到的总伤害时,它才会死亡。
计算每一轮中死亡的怪物数量。
输入:
第一行包含一个整数 t ( 1 ≤ t ≤ 10^4) - 测试用例数。
每个测试用例由三行组成:
- 第一行包含一个整数 n ( 1≤n≤3?10^5 );
- 第二行包含 n 个整数 a1,a2,…,an1,2,…, ( 1≤ai≤10^9 )( 1≤ai≤10^9 );
- 第三行包含 n 个整数 d1,d2,…,dn1,2,…, ( 1≤di≤109 )。
输入的附加限制:所有测试用例的 n 之和不超过 3?10^5。
输出:
对于每个测试案例,打印 n 个整数。 i 个整数应该等于在 i 个回合中死亡的怪物数量。
样例1
3 5 3 4 7 5 10 4 9 1 18 1 2 2 1 1 3 4 1 1 2 4 3 3 4 2
3 1 0 0 0 0 0 1 1 1 0
思路:
首先思考一个怪物在什么情况下会死亡呢
两种情况
- 一开始的时候就被周围的怪物弄死了
- 剩下的就是第一回和没死的,假设上一回和没死的怪物,周围的怪都没死,那么他受的伤害和上一回和相同,依旧可以存活,也就是说只有上一回合旁边的怪物死了,才有可能死亡。
解决办法:
- 对于第一种情况,只能进行预处理
- 对于第二种情况,那就是记录上一回合死亡的怪物然后再出来与他相邻的怪物
怎么快速获取死亡怪物附近的两个怪物呢,可以记录左右节点,利用数组存储,实现复杂,对于连续死多个处理麻烦,利用链表,又无法快速获取下标。
使用stl容器的set,利用其中的upper_bound快速找到他的下一个位置的怪物,那么怎么找前一个呢,利用greater<int>将set反序,由于upper_bound找到的是等于自己的下一个元素,那么对于反序的就是小于自己的第一个元素,也就是前一个坐标,然后判断是否存在,在利用左右两边怪物的攻击判断是否能够击杀,能就用队列现存下来,然后再在set当中删除他的下标,再循环此操作
#include<bits/stdc++.h> using namespace std; #define x first #define y second #define Yes cout << "Yes " #define No cout << "No " #define YES cout << "YES " #define NO cout << "NO " #define ls u << 1 #define rs u << 1 | 1 #define all(x) x.begin(),x.end() // #define int long long #define i128 __int128 inline int gcd(int a, int b) {return b > 0 ? gcd(b, a % b) : a;} inline int lowbit(int x) {return x & (-x);} int qmi(int a, int b, int mod){int res = 1;while(b) {if(b & 1) res = res * a % mod;a = a * a % mod;b >>= 1;}return res;} inline i128 read(){i128 x = 0, f = 1;char ch = getchar();while(ch < '0' || ch > '9'){if(ch == '-')f = -1;ch = getchar();}while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}return x * f;} inline void print(i128 x){if(x < 0){putchar('-');x = -x;}if(x > 9)print(x / 10);putchar(x % 10 + '0');} typedef long long ll; typedef pair<int, int> PII; typedef pair<PII, int> PIII; const int N = 1e5 + 10, inf = 0x3f3f3f3f, mod = 1e9 + 7; /* int mp[N + 1]; vector<int>prim; void primes() { for (int i = 2; i <= N; i++) { if (!mp[i]) { mp[i] = i; prim.push_back(i); } for (auto p : prim) { if (i * p > N) break; mp[i * p] = p; if (i % p == 0) break; } } } */ /* int fact[N], infact[N]; // 组合数 int C(int a, int b) {return fact[a] * infact[b] % mod * infact[a - b] % mod;} void combination() {fact[0] = infact[0] = 1;for(int i = 1; i < N; i ++) {fact[i] = fact[i - 1] * i % mod;infact[i] = fact[i] * qmi(i, mod - 2, mod) % mod;}} */ void solve() { int n; cin >> n; vector<int>a(n + 1, 0), d(n + 1, 0); set<int>stx; set<int, greater<int>>sti; for(int i = 1; i <= n; i ++) cin >> a[i]; for(int i = 1; i <= n; i ++) cin >> d[i], stx.insert(i), sti.insert(i); vector<int>c(n + 2, 0); for(int j = 1; j <= n; j ++) { c[j - 1] += a[j], c[j + 1] += a[j]; } set<int>s; for(int i = 1; i <= n; i ++) if(c[i] > d[i]) s.insert(i), stx.erase(i), sti.erase(i); vector<bool>stb(n + 1, 0); for(int j = 1; j <= n; j ++) { cout << s.size() << ' '; vector<int>v; for(auto t : s) { auto itx = stx.upper_bound(t); int ans = 0; if(itx != stx.end()) { int p = *itx; auto itxx = stx.upper_bound(p); auto itxi = sti.upper_bound(p); if(itxx != stx.end()) ans += a[*itxx]; if(itxi != sti.end()) ans += a[*itxi]; if(ans > d) v.push_back(p); } auto iti = sti.upper_bound(t); ans = 0; if(iti != sti.end()) { int p = *iti; auto itix = stx.upper_bound(p); auto itii = sti.upper_bound(p); if(itix != stx.end()) ans += a[*itix]; if(itii != sti.end()) ans += a[*itii]; if(ans > d) v.push_back(p); } } s.clear(); for(auto k : v) s.insert(k), stx.erase(k), sti.erase(k); } cout << ' '; } signed main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int t = 1; cin >> t; while (t--) { solve(); } }