首先感谢 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;
}

京公网安备 11010502036488号