【2020NOI.AC省选模拟】C. 送分题

题目链接

原题解:

从前往后扫描序列,维护当前可能出现在答案中的候选序列。

每当我们遇到一个不在候选序列中的数$x$时,若当前序列中最后一个数$y$在未被扫描得部分中也出现过,且$y>x$,我们可以把$y$弹出候选序列。

重复此操作,然后把$x$加入候选队列。每个元素最多进栈出栈一次,时间复杂度为$O(n)$。

补充:

描述一个我的半暴力的做法。

设置一个序列$s$,初始在每种数最后出现的位置填$0$,其他填$0$。

尝试找$k$轮,每轮找出接下来填的数字。

用树状数组求$s$的后缀和来二分,找出后缀和最大的下标中最靠后的,设为$p$。

设上一次取数的位置为$pre$,那么本轮就可以在$[pre+1,p]$中暴力找最小的数字中的第一个,然后把它在$s$上的影响消去。

这个做法可以AC,但是用时1600ms,算最慢的一档。其他的算法有700ms,1000ms和1300ms三档。

这个复杂度乍一看不太对,因为我们每次会暴力在一个区间里找最小值。

仔细思考一下,说不出个所以然来,但感觉这个暴力找的区间长度和重合度都不会特别高……之类的?然后就能过。不过NOI.AC的数据强度不敢特别恭维……

 

代码(100分):

【2020NOI.AC省选模拟】C. 送分题
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<set>
#define IL inline
#define RG register
#define _1 first
#define _2 second
using namespace std;
#define RI RG int
#define RC RG char
const int N=2e6;

IL void qr(RI &x){
    x=0;    RC ch=getchar();
    while(!isdigit(ch))    ch=getchar();
    for(;isdigit(ch);ch=getchar())    x=(x<<3)+(x<<1)+ch-'0';
}

IL void qw(RI x,RC ch){
    RI k=0,s[13];
    for(;x;x/=10)    s[++k]=x%10;
    for(;k;k--)    putchar(s[k]+'0');
    putchar(ch);
}

    int n,k,a[N+3];
    int v[N+3];
    int s[N+3];

IL int lowbit(RI x){return x&(-x);}

IL void mdf(RI p,RI x){
    p=n-p+1;
    for(;p<=n;p+=lowbit(p))
        s[p]+=x;
}

IL int qry(RI p){
    p=n-p+1;
    RI ret=0;
    for(;p;p-=lowbit(p))
        ret+=s[p];
    return ret;
}

IL int sol(RI x){
    RI l=1,r=n,mid,ans;
    while(l<=r){
        mid=(l+r)>>1;
        if(qry(mid)>=x){
            l=mid+1;    ans=mid;
        }
        else 
            r=mid-1;
        
    }
    return ans;
    
}

    int ans[N+3];

int main(){
    qr(n);    qr(k);
    for(RI i=1;i<=n;i++)
        qr(a[i]);
        
    for(RI i=n;i>=1;i--)
    if(!v[a[i]]){
        v[a[i]]=i;
        mdf(i,1);
        
    }
    
    a[n+1]=k+1;
    for(RI i=1,p,x,pre=0;i<=k;i++){
        p=sol(k-i+1);
        x=n+1;
        for(RI j=pre+1;j<=p;j++)
        if(v[a[j]]&&a[j]<a[x])
            x=j;
        ans[i]=a[x];
        mdf(v[a[x]],-1);
        v[a[x]]=0;
        pre=x;
        
    }
    
    for(RI i=1;i<=k;i++)
        qw(ans[i],' ');
    
    return 0;

}
View Code

 

上一篇:CF1045G AI robots


下一篇:牛客国庆训练 H.千万别用树套树