zoukankan      html  css  js  c++  java
  • 【2020NOI.AC省选模拟#2】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分):

    #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
  • 相关阅读:
    五、生产者消费者模型_ThreadLocal
    四、多线程基础-线程池的创建和使用
    spring根据beanName获取bean
    spring容器的功能扩展
    机甲大师S1机器人编程学习,Windows 10 安装Scratch和简单实例学习
    如何建设高可用系统
    详解Condition的await和signal等待/通知机制
    从源码角度彻底理解ReentrantLock(重入锁)
    MySQL 分库分表及其平滑扩容方案
    机甲大师S1机器人编程学习
  • 原文地址:https://www.cnblogs.com/Hansue/p/13032004.html
Copyright © 2011-2022 走看看