• [线段树][ST表][堆]luogu P5967 [POI2016]Korale


    题面

    https://www.luogu.com.cn/problem/P5967

    分析

    看这种可以线性扩展且要求第 k 小的问题,就容易想到超级钢琴的做法

    初始将一个 (a[1],1) 加入小根堆 (sum,i) ,每次取出堆顶时可以扩展为 (sum+a[i+1],i+1) , (sum-a[i]+a[i+1],i+1) (i<n) 显然取出到第 k 个时即为第 k 小(k 预先减 1 除去 0 的情况)

    那么考虑大小相同的情况,我们用一个 cnt 来记录

    因为要求字典序最小,所以搜索的时候贪心地选择靠前的且小于当前值 sum 的,可以用线段树或者 ST表 来维护这个最小值

    ST表占用内存过高,会影响运行速度,最后用的线段树

    代码

    #include <iostream>
    #include <cstdio>
    #include <queue>
    #include <stack>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    const int Inf=1e9+1;
    const int N=1e6+10;
    struct Sum {
        ll val;int id;
        friend bool operator < (Sum a,Sum b) {return a.val>b.val;}
    };
    int n,k,m,same,pw[20],lg2[N],a[N],f[N][20];
    ll ans;
    priority_queue<Sum>q;
    int s[N],top;
    bool fin;
    
    inline int read(){
        register int s=0,w=1;
        char ch=getchar();
        while (ch<'0'||ch>'9'){if (ch=='-')w=-1;ch=getchar();}
        while (ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
        return s*w;
    }
    
    inline void write(int x) {
        if(x>9) write(x/10);putchar(x%10+48);return;
    }
    
    inline int Min(int l,int r) {return min(f[l][lg2[r-l+1]],f[r-pw[lg2[r-l+1]]+1][lg2[r-l+1]]);}
    
    inline void DFS(int dep,ll sum) {
        if (!sum) {
            same--;
            if (!same) {
                for (register int i=1;i<=top;i++) write(s[i]),putchar(32);
                fin=1;
            }
            return;
        }
        if (dep>n) return;
        for (register int i=dep;i<=n;i++) {
            register int l=i,r=n;
            while (l<=r) {
                register int mid=l+r>>1;
                if (Min(l,mid)<=sum) i=mid,r=mid-1;
                else l=mid+1;
            }
            if (!i) return;
            s[++top]=i;DFS(i+1,sum-f[i][0]);
            top--;if (fin) return;
        }
    }
    
    int main() {
        n=read(),k=read();m=log2(n);
        pw[0]=1;for (register int i=1;i<=m;i++) pw[i]=pw[i-1]<<1;
        for (register int i=1,j=0;i<=n;i++) a[i]=read(),f[i][0]=a[i],lg2[i]=j,j+=(i==pw[j]);
        for (register int i=1;i<=m;i++)
            for (register int j=1;j+pw[i]-1<=n;j++) f[j][i]=min(f[j][i-1],f[j+pw[i-1]][i-1]);
        sort(a+1,a+n+1);q.push((Sum){a[1],1});
        same=1;ans=0;
        for (register int i=1;i<k;i++) {
            register Sum now=q.top();q.pop();
            if (now.val>ans) ans=now.val,same=0;
            if (now.val==ans) same++;
            if (now.id<n) q.push((Sum){now.val-a[now.id]+a[now.id+1],now.id+1}),q.push((Sum){now.val+a[now.id+1],now.id+1});
        }
        printf("%lld
    ",ans);
        DFS(1,ans);
    }
    ST表版
    //ST占内存太高过不了 
    #include <iostream>
    #include <cstdio>
    #include <queue>
    #include <algorithm>
    #define lson (x<<1)
    #define rson ((x<<1)+1)
    using namespace std;
    typedef long long ll;
    const int Inf=1e9+1;
    const int N=1e6+10;
    struct Sum {
        ll val;int id;
        friend bool operator < (Sum a,Sum b) {return a.val>b.val;}
    };
    int n,k,m,same,a[N],t[4*N],rev[N];
    ll ans;
    priority_queue<Sum>q;
    int s[N],top;
    bool fin;
    
    inline int read(){
        register int s=0,w=1;
        char ch=getchar();
        while (ch<'0'||ch>'9'){if (ch=='-')w=-1;ch=getchar();}
        while (ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
        return s*w;
    }
    
    inline void write(int x) {
        if(x>9) write(x/10);putchar(x%10+48);return;
    }
    
    inline void Build(int x,int l,int r) {
        if (l==r) {t[rev[l]=x]=a[l];return;}
        int mid=l+r>>1;
        Build(lson,l,mid);Build(rson,mid+1,r);
        t[x]=min(t[lson],t[rson]);
    }
    
    inline int Query(int x,int l,int r,int k,ll lim) {
        if (k<=l) {
            if (t[x]>lim) return 0;
            if (l==r) return l;
        }
        int mid=l+r>>1,lef=0;
        if (k<=mid) lef=Query(lson,l,mid,k,lim);
        if (lef) return lef;
        return Query(rson,mid+1,r,k,lim);
    }
    
    inline void DFS(int dep,ll sum) {
        if (!sum) {
            same--;
            if (!same) {
                for (register int i=1;i<=top;i++) write(s[i]),putchar(32);
                fin=1;
            }
            return;
        }
        if (dep>n) return;
        for (register int i=dep;i<=n;i++) {
            if (!(i=Query(1,1,n,i,sum))) return;
            s[++top]=i;DFS(i+1,sum-t[rev[i]]);
            top--;if (fin) return;
        }
    }
    
    int main() {
        n=read(),k=read();
        for (register int i=1,j=0;i<=n;i++) a[i]=read();
        Build(1,1,n);sort(a+1,a+n+1);q.push((Sum){a[1],1});
        same=1;ans=0;
        for (register int i=1;i<k;i++) {
            register Sum now=q.top();q.pop();
            if (now.val>ans) ans=now.val,same=0;
            if (now.val==ans) same++;
            if (now.id<n) q.push((Sum){now.val-a[now.id]+a[now.id+1],now.id+1}),q.push((Sum){now.val+a[now.id+1],now.id+1});
        }
        printf("%lld
    ",ans);
        DFS(1,ans);
    }
    线段树版
    在日渐沉没的世界里,我发现了你。
  • 相关阅读:
    C++虚函数表解析(转)
    学习网址
    css 段落文字换行问题
    移动端fixed兼容问题
    半数集1
    汇编寄存器
    设计模式概述
    Vector用法介绍
    汇编PC硬件基本特征
    android 反编译总结
  • 原文地址:https://www.cnblogs.com/mastervan/p/14578854.html
Copyright © 2020-2023  润新知