NC14583 糖糖别胡说,我真的不是签到题目

题目

题目描述

从前,有 \(n\) 只萌萌的糖糖,他们分成了两组一起玩游戏。他们会排成一排,第 \(i\) 只糖糖会随机得到一个能力值 \(b_i\)。从第 \(i\) 秒的时候,第 \(i\) 只糖糖就可以消灭掉所有排在他前面的和他不是同一组的且能力值小于他的糖糖。

为了使游戏更加有趣,糖糖的爸爸,娇姐,会发功 \(m\) 次,第 \(i\) 次发功的时间为 \(c_i\) ,则在第 \(c_i\) 秒结束后 \(b_1,b_2,.....,b_{c_i}\) 都会增加 \(1\)

现在,娇姐想知道在第 \(n\) 秒后,会有多少只糖糖存活下来。

输入描述

第一行只有一个整数 \(T\)\(T<6\)) ,表示测试数据的组数。
第二行有两个整数 \(n,m\) 。表示糖糖的个数以及娇姐发功的次数。(\(1 \leq n\leq 50000,1 \leq b_i \leq 1000000\)
第三行到 \(n+2\) 行,每行有两个整数 \(a_i,b_i\) ,表示第 \(i\) 只糖糖属于那一组以及他的能力值。(\(0\leq a_i \leq 1,1\leq b_i\leq 1000000\)
\(n+3\) 行到第 \(n+m+2\) 行,每行有一个整数 \(c_i\) ,表示GTW第 \(i\) 次发功的时间.(\(1\leq c_i \leq n\))

输出描述

总共 \(T\) 行,第 \(i\) 行表示第 \(i\) 组数据中,糖糖存活的个数。

示例1

输入

1 
4 3 
0 3 
1 2 
0 3 
1 1 
1 
3 
4

输出

3

题解

知识点:枚举,前缀和,差分。

每一只糖糖的状态之和后面的糖糖有关,从正向遍历每次要重复考虑之前区间糖糖的状态,从反向遍历可以通过更新已遍历区间的最大值来决定遍历到的糖糖的状态。

\(i\) 次发功后会造成 \([0,c_i]\) 糖糖数值加一,显然每次增加不会影响后面的糖糖状态。正向遍历每次都给对应区间整体加一,不能满足复杂度;反向遍历用 \(delta\) 来记录到某个糖糖为止增加的次数,从而在之后用 \(b_i+delta\) 代替 \(b_i\) 达到增加的效果。

时间复杂度 \(O(n+m)\)

空间复杂度 \(O(n+m)\)

代码

#include <bits/stdc++.h>

using namespace std;

bool a[50007];
int b[50007];
int c[50007];

int main(){
    std::ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int T;
    cin>>T;
    while(T--){
        int n,m;
        cin>>n>>m;
        for(int i = 1;i<=n;i++){
            c[i] = 0;
            cin>>a[i]>>b[i];
        }
        for(int i = 0;i<m;i++){
            int tmp;
            cin>>tmp;
            c[tmp]++;
        }

        int delta = 0,ans = n,max0 = 0,max1 = 0;
        ///一个糖糖的死活只和后面糖糖最大值有关
        for(int i = n;i>=1;i--){
            delta+=c[i];///区间增值是向前的,所以可以逆向累加
            if(a[i]){
                ans -= (b[i]+delta)<max0;
                max1 = max(b[i]+delta,max1);
            }
            else{
                ans -= (b[i]+delta)<max1;
                max0 = max(b[i]+delta,max0);///更新最大值为当前值+增值
            }
        }
        cout<<ans<<'\n';
    }
    return 0;
}
posted @ 2022-05-09 10:22  空白菌  阅读(40)  评论(0编辑  收藏  举报