• #3636. IIIDX(iiidx)


    题目描述

    Osu 听过没?那是 Konano 最喜欢的一款音乐游戏,而他的梦想就是有一天自己也能做个独特酷炫的音乐游戏。现在,他在世界知名游戏公司 KONMAI 内工作,离他的梦想也越来越近了。

    这款音乐游戏内一般都包含了许多歌曲,歌曲越多,玩家越不易玩腻。同时,为了使玩家在游戏上~~氪更多的金钱~~花更多的时间,游戏一开始一般都不会将所有曲目公开,有些曲目你需要通关某首特定歌曲才会解锁,而且越晚解锁的曲目难度越高。

    这一天,Konano 接到了一个任务,他需要给正在制作中的游戏《IIIDX》安排曲目的解锁顺序。游戏内共有 $n$ 首曲目,每首曲目都会有一个难度 $d$,游戏内第 $i$ 首曲目会在玩家 Pass 第 $leftlfloor frac i k ight floor$ 首曲目后解锁($leftlfloor x ight floor$ 为下取整符号)若 $leftlfloor frac i k ight floor = 0$,则说明这首曲目**无需解锁**。

    举个例子:当 $k = 2$ 时,第 $1$ 首曲目是无需解锁的($leftlfloor frac 12 ight floor = 0$),第 $7$ 首曲目需要玩家 Pass 第 $leftlfloor frac 72 ight floor = 3$ 首曲目才会被解锁。

    Konano 的工作,便是安排这些曲目的顺序,使得每次解锁出的曲子的难度**不低于**作为条件需要玩家通关的曲子的难度,即使得确定顺序后的曲目的难度对于每个 $i$ 满足 $d_i geq d_{leftlfloor frac ik ight floor}$。

    数据范围

    $1 le n le 5 imes 10^5,1 le k,d le 10^9$

    题解

    (此处省略错误贪心)

    转化成有根树,然后考虑从 $1 sim n$ 放数,将 $d$ 从大到小排序。

    对于每个数 $x$ ,我们想要其最大,所以我们可以设 $f_i$ 为 $i$ 前还能放的位置,然后找到最靠前的 $i$ ,使得 $min{f_j}(j in [i,n]) ge size_x$ 即可,然后找到和 $i$ 相同的数的最后一个位置 $j$ ,将 $[j,n]$ 的位置的 $f$ 都减去 $size_x$ 即可,这些操作用线段树维护即可。

    注意要把父亲的 $size$ 加回来

    代码

    #include <bits/stdc++.h>
    #define db double
    using namespace std;
    const int N=5e5+5; db k;
    int n,d[N],fa[N],sz[N],pr[N],a[N],in[N<<2],tg[N<<2];
    #define Ls u<<1
    #define Rs u<<1|1
    #define mid ((l+r)>>1)
    void build(int u,int l,int r){
        in[u]=l; if (l==r) return;
        build(Ls,l,mid);build(Rs,mid+1,r);
    }
    void push(int u,int v){tg[u]+=v;in[u]+=v;}
    void down(int u){
        push(Ls,tg[u]);push(Rs,tg[u]);tg[u]=0;
    }
    void upd(int u,int l,int r,int x,int v){
        if (x<=l) return push(u,v);
        if (tg[u]) down(u);
        if (mid>=x) upd(Ls,l,mid,x,v);
        upd(Rs,mid+1,r,x,v);
        in[u]=min(in[Ls],in[Rs]);
    }
    int find(int u,int l,int r,int v){
        if (l==r) return l+(in[u]<v);
        if (tg[u]) down(u);
        if (in[Rs]>=v) return find(Ls,l,mid,v);
        return find(Rs,mid+1,r,v);
    }
    int main(){
        cin>>n>>k;
        for (int i=1;i<=n;i++)
            scanf("%d",&d[i]),sz[i]=1,
            fa[i]=(int)((db)i/k);
        sort(d+1,d+n+1);
        reverse(d+1,d+n+1);
        for (int i=n;i;i--)
            sz[fa[i]]+=sz[i],
            pr[i]=d[i]==d[i+1]?pr[i+1]+1:0;
        build(1,1,n);
        for (int j,i=1;i<=n;i++){
            if (fa[i] && fa[i]!=fa[i-1])
                upd(1,1,n,a[fa[i]],sz[fa[i]]-1);
            j=find(1,1,n,sz[i]);
            j+=pr[j];pr[j]++;j-=(pr[j]-1);
            a[i]=j;upd(1,1,n,j,-sz[i]);
        }
        for (int i=1;i<=n;i++)
            printf("%d",d[a[i]]),
            putchar(i<n?' ':'
    ');
        return 0;
    }
  • 相关阅读:
    Python:Pandas的基本操作和使用
    奇技淫巧:绝佳笔记篇-wolai
    Scala:(五) 类、对象、继承、模式匹配和样例类
    tree2List
    java mybatis多层collection嵌套查询
    linux 查看目录下各个文件的大小
    Redisson使用手册
    hutool 定时任务 TimedCache
    清理Docker占用的磁盘空间
    java线程池
  • 原文地址:https://www.cnblogs.com/xjqxjq/p/11779086.html
Copyright © 2020-2023  润新知