牛客算法競賽入門課第一節習題 糖糖別胡說,我真的不是簽到題目(前綴和+思維)

題目鏈接:https://ac.nowcoder.com/acm/problem/14583

題目描述
從前,有n只萌萌的糖糖,他們分成了兩組一起玩遊戲。他們會排成一排,第i只糖糖會隨機得到一個能力值bi。從第i秒的時候,第i只糖糖就可以消滅掉所有排在他前面的和他不是同一組的且能力值小於他的糖糖。
爲了使遊戲更加有趣,糖糖的爸爸,嬌姐,會發功m次,第i次發功的時間爲ci,則在第ci秒結束後,b1,b2,…,bci都會增加1.
現在,嬌姐想知道在第n秒後,會有多少隻糖糖存活下來。

輸入描述:
第一行只有一個整數T(T<6),表示測試數據的組數。
第二行有兩個整數n,m。表示糖糖的個數以及嬌姐發功的次數。(1<=n<=50000,1<=bi<=1000000)
第三行到n+2行,每行有兩個整數ai,bi,表示第i只糖糖屬於那一組以及他的能力值。(0<=ai<=1,1<=bi<=1000000)
第n+3行到第n+m+2行,每行有一個整數ci,表示GTW第i次發功的時間.(1<=ci<=n)
輸出描述:
總共T行,第i行表示第i組數據中,糖糖存活的個數。

輸入

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

輸出

3

分析:

最開始想的,外層循環從1到n枚舉每一個糖糖,碰到發功的時刻i,對於小於i的糖糖戰鬥力++,時間複雜度n2n^2,超時。

對於每一個發功的時刻,其前面的糖糖的戰鬥力都要加1,可以前綴和維護第i秒時一共發功了多少次。
sum[i]:第i秒時,一共發功了sum[i]次
假設:j<i
編號爲j的糖糖的戰鬥力增加了sum[i]-sum[j-1]
編號爲i的糖糖的戰鬥力增加了sum[i]-sum[i-1]

若j位置的糖糖被i位置的糖糖消去的條件是:
j<i && group[j]!=group[i] && fight[j]<fight[i]

fight[j]=fight[j]+sum[i]-sum[j-1]
fight[i]=fight[i]+sum[i]-sum[i-1]

fight[j]<fight[i]可以轉化爲
fight[j]-sum[j-1]<fight[i]-sum[i-1]

細節條件:所有的糖糖要麼是0組的,要麼是1組的

s[0],s[1]分別記錄所在組的最大的fight[i]-sum[i-1]
倒着掃描,更新最大值

        int s[2];
        s[0]=s[1]=-2e7;
        int res=n;
        for(int i=n; i>=1; i--)
        {
            if(fight[i]<s[group[i]^1])///group[i]^1記錄不同組,因爲是倒序的,s[group[i]^1]記錄的是比此時的i大的戰鬥力
                res--;
            s[group[i]]=max(s[group[i]],fight[i]);
        }

完整代碼:

#include<iostream>
#include<string>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=5*1e4+10;
int group[N];
int fight[N];
int sum[N];
int n,m;
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        for(int i=1; i<=n; i++)
        {
            scanf("%d%d",&group[i],&fight[i]);
            sum[i]=0;
        }
        while(m--)
        {
            int x;
            scanf("%d",&x);
            sum[x]+=1;
        }
        for(int i=1; i<=n; i++)
        {
            sum[i]+=sum[i-1];///前綴和 第i秒時一共加了sum[i]
            fight[i]-=sum[i-1];
        }
        int s[2];
        s[0]=s[1]=-2e7;///初值一定要大
        int res=n;
        for(int i=n; i>=1; i--)
        {
            if(fight[i]<s[group[i]^1])
                res--;
            s[group[i]]=max(s[group[i]],fight[i]);
        }
        printf("%d\n",res);
    }
    return 0;
}
/*
1
4 3  4個人  發功3
0 3   屬於哪一組  能力值
1 2
0 3
1 1
1 3 4  發功的時間*/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章