传送门:​​点击打开链接​

题意:n个GT排列在一起,他们有两组,有可能是第0组的,也有可能是第1组的。每个人都有一个能力值。每次第i秒第i个人都会对他前面的另一组的人发起攻击,如果能力值比他低,就会退出游戏。另外还有m个数字Ci,在第Ci秒末尾的时候,前Ci个存活的人的能力都会+1,问最后剩余的人数

思路:很明显可以逆推。用isc[i]表示有多少个Ci等于i,s[i]表示isc在前i个的前缀和。那么会有Max > A[i] + s[Maxid - 1] - s[i - 1],Max表示在第i个的后面的对手里面的能力的最大值,Maxid表示最大值的id,然后变换一下就有Max - s[Maxid - 1] > A[i]  - s[i - 1],所以我们只要倒着维护Max - s[Maxid - 1]的最大值就可以了。

#include<map>
#include<set>
#include<cmath>
#include<ctime>
#include<stack>
#include<queue>
#include<cstdio>
#include<cctype>
#include<string>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
#define fuck(x) cout<<"["<<x<<"]"
#define FIN freopen("input.txt","r",stdin)
#define FOUT freopen("output.txt","w+",stdout)
using namespace std;
typedef long long LL;

const int MX = 1e5 + 5;
const int INF = 0x3f3f3f3f;

struct Data {
int val, id;
} A[MX];

int isc[MX], s[MX];

int main() {
int T, n, m; //FIN;
scanf("%d", &T);
while(T--) {
memset(isc, 0, sizeof(isc));
memset(s, 0, sizeof(s));

scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++) {
scanf("%d%d", &A[i].id, &A[i].val);
}
for(int i = 1; i <= m; i++) {
int t; scanf("%d", &t);
isc[t]++;
}
s[0] = 0;
for(int i = 1; i <= n; i++) {
s[i] = s[i - 1] + isc[i];
}

int Max[2] = { -INF, -INF}, ans = 0;
for(int i = n; i >= 1; i--) {
if(Max[A[i].id ^ 1] > A[i].val - s[i - 1]) {
ans++;
}
Max[A[i].id] = max(Max[A[i].id], A[i].val - s[i - 1]);
}
printf("%d\n",n - ans);
}
return 0;
}