首先感谢 PDSU----18计一-----周宁 ,我是看了这位大佬的解题,然后获取了一些思路。
题目意思:
第i个糖糖会有bi的能力值,然后他父亲能够在第i秒把1-i位置的b能力值都加1.
第i个糖糖在第i秒能干掉前面比他能力值小的人,并且是不用小组的,同一小组是不能干的。
小组最多就2组。
思路:首先我们需要先预处理父亲在每个时间点,对整体答案的影响。先计算算出来!
样例给出的是 bi:3 2 3 1 经过4秒钟之后的结果是 6 4 5 2
然后我们就发现,很显然,3号能攻击2号,因为5>4 并且2号和3号不在同一组
这样的话,我们从后往前就很好处理了
复杂度也降为O(n)
首先怎么处理父亲的时间点,bi增加的值,是父亲时间点的次数,应该从后往前进行求时间点的前缀和,然后给bi加上去。这样就把父亲的贡献给加上去了
接下来就是怎么计算那些人是没***掉的
因为总共就2组,我们可以从后往前跑,这样保证的是i<j,然后维护2个最大值,分别是第一组的最大值max1,第二组的最大值max2。我们这里的最大值是从后往前的最大值,并不是从前往后的最大值
如果当前这个点在第二组,如果比第一组的最大值还要大,那说明什么呢,这个点是不会被攻击到的,因为他比另一组的最大值还要大。
注意点: 初始化不要忘记
AC代码:
#include <iostream> #include <algorithm> #include <cstdio> #include <cstring> #include <string> #include <vector> #include <map> #include <queue> #include <deque> #include <set> #include <stack> #include <cctype> #include <cmath> #include <cassert> using namespace std; typedef long long ll; const ll mod=1000000007; ll powmod(ll a,ll b) {ll res=1;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;} ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;} const int N=50000+100; int t; int n,m; int x,y; int g[N];//分组 int a[N];//对应的能力 int _time[N]; void init() { memset(g,0,sizeof(g)); memset(a,0,sizeof(a)); memset(_time,0,sizeof(_time)); } int main() { scanf("%d",&t); while(t--) { init(); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d%d",&x,&y); a[i]=y; g[i]=x; } for(int i=1;i<=m;i++) { scanf("%d",&x); _time[x]++; } for(int i=n;i>0;i--) { _time[i]+=_time[i+1];//当前时间点发功了几次,相当于从后往前求前缀和 //a[]: 3 2 3 1 //time[]: 1 0 1 1 a[i]+=_time[i]; } // for(int i=1;i<=n;i++) // { // printf("%d%c",a[i]," \n"[i==n]); // } int max1=-1;//表示第一组最大值 int max2=-1;//表示第二组最大值 int ans=0; for(int i=n;i>=1;i--) { if(g[i]==0) {//0表示第一组 if(a[i]>=max2) {//如果当前的值大于第二组的最大值了,那么ans++; //也就是说当前这个点是不会被杀的 ans++; } if(a[i]>max1) { max1=a[i]; } } else { if(a[i]>=max1) {//如果当前的值大于第二组的最大值了,那么ans++; ans++; } if(a[i]>max2) { max2=a[i]; } } } printf("%d\n",ans); } return 0; }