题意
从前,有n只萌萌的糖糖,他们分成了两组一起玩游戏。他们会排成一排,第i只糖糖会随机得到一个能力值bi。从第i秒的时候,第i只糖糖就可以消灭掉所有排在他前面的和他不是同一组的且能力值小于他的糖糖。
为了使游戏更加有趣,糖糖的爸爸,娇姐,会发功m次,第i次发功的时间为ci,则在第ci秒结束后,b1,b2,.....,bci都会增加1.
现在,娇姐想知道在第n秒后,会有多少只糖糖存活下来。
分析
考虑第 只糖糖能杀死多少只糖糖不太好想,那我们来看第 只糖糖会不会被杀死。
我们记 为第 只糖糖在第 秒的时候的能力值增量, 为 的前缀和。
假设第 只糖糖会在第 秒被杀死,即是被第 只糖糖杀死,那么需满足的条件:
也就是 秒的时候,第只糖糖的能力值小于 第只糖糖的能力值。
那我们移一下项,就有:
也就是说,存在 ,使得该式成立。那么我们对 做一个后缀 就可以了。
复杂度
代码如下
#include <bits/stdc++.h> #include<ext/pb_ds/hash_policy.hpp> #include<ext/pb_ds/assoc_container.hpp> #define N 50005 using namespace __gnu_pbds; using namespace std; typedef long long LL; typedef unsigned long long uLL; struct custom_hash { static uint64_t splitmix64(uint64_t x) { x += 0x9e3779b97f4a7c15; x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9; x = (x ^ (x >> 27)) * 0x94d049bb133111eb; return x ^ (x >> 31); } size_t operator()(uint64_t x) const { static const uint64_t FIXED_RANDOM = chrono::steady_clock::now().time_since_epoch().count(); return splitmix64(x + FIXED_RANDOM); } }; LL z = 1; int read(){ int x, f = 1; char ch; while(ch = getchar(), ch < '0' || ch > '9') if(ch == '-') f = -1; x = ch - '0'; while(ch = getchar(), ch >= '0' && ch <= '9') x = x * 10 + ch - 48; return x * f; } int ksm(int a, int b, int p){ int s = 1; while(b){ if(b & 1) s = z * s * a % p; a = z * a * a % p; b >>= 1; } return s; } int s[N], a[N], b[N], c[N], m1[N], m2[N]; int main(){ int i, j, n, m, T, tot; T = read(); while(T--){ n = read(); m = read(); for(i = 1; i <= n; i++) b[i] = read(), a[i] = read(); for(i = 1; i <= n; i++) m1[i] = m2[i] = -1e9, c[i] = s[i] = 0; for(i = 1; i <= m; i++) c[read()]++; for(i = 1; i <= n; i++) s[i] = s[i - 1] + c[i]; m1[n + 1] = m2[n + 1] = 0; for(i = n; i >= 1; i--){ m1[i] = m1[i + 1], m2[i] = m2[i + 1]; if(b[i] == 1) m1[i] = max(m1[i], a[i] - s[i - 1]); else m2[i] = max(m2[i], a[i] - s[i - 1]); } tot = n; for(i = 1; i < n; i++){ if(b[i] == 1 && a[i] - s[i - 1] < m2[i + 1]) tot--; if(b[i] == 0 && a[i] - s[i - 1] < m1[i + 1]) tot--; } printf("%d\n", tot); } return 0; }