5249: [2018多省省队联测]IIIDX

Description

【题目背景】

Osu听过没?那是Konano最喜欢的一款音乐游戏,而他的梦想就是有一天自己也能做个独特酷炫的音乐游戏。现在,他在世界知名游戏公司KONMAI内工作,离他的梦想也越来越近了。这款音乐游戏内一般都包含了许多歌曲,歌曲越多,玩家越不易玩腻。同时,为了使玩家在游戏上氪更多的金钱花更多的时间,游戏一开始一般都不会将所有曲目公开,有些曲目你需要通关某首特定歌曲才会解锁,而且越晚解锁的曲目难度越高。

【题目描述】

这一天,Konano接到了一个任务,他需要给正在制作中的游戏《IIIDX》安排曲目的解锁顺序。游戏内共有n首曲目,每首曲目都会有一个难度d,游戏内第i首曲目会在玩家Pass第trunc(i/k)首曲目后解锁(x为下取整符号)若trunc(i/k)=0,则说明这首曲目无需解锁。举个例子:当k=2时,第1首曲目是无需解锁的(trunc(1/2)=0),第7首曲目需要玩家Pass第trunc(7/2)=3首曲目才会被解锁。Konano的工作,便是安排这些曲目的顺序,使得每次解锁出的曲子的难度不低于作为条件需要玩家通关的曲子的难度,即使得确定顺序后的曲目的难度对于每个i满足Di≥Dtrunc(i/k)。当然这难不倒曾经在信息学竞赛摸鱼许久的Konano。那假如是你,你会怎么解决这份任务呢?

Input

第1行1个正整数n和1个小数k,n表示曲目数量,k其含义如题所示。

第2行n个用空格隔开的正整数d,表示这n首曲目的难度。

1 ≤ n ≤ 500000

1 < k ≤ 10^9

1 < d ≤ 10^9

Output

输出1行n个整数,按顺序输出安排完曲目顺序后第i首曲目的难度。

若有多解,则输出d1最大的;若仍有多解,则输出d2最大的,以此类推。

Sample Input

4 2.0
114 514 1919 810

Sample Output

114 810 514 1919

题解

我们可以把限制关系抽象成森林,第\(i\)个结点的父亲是第\(\left \lfloor \frac{i}{k} \right \rfloor\)个结点。如果新建一个根\(0\)号节点,并从\(0\)向所有树的根连边,就会形成一棵树。这样题目就变成了把数安放到一个树上使得儿子比父亲大,同时解的字典序还要最大。

考虑贪心,将数从大到小排序,按照编号顺序依次确定每个节点所填的数。为了保证儿子比父亲填的数大,在填某个节点\(i\)的数时,假设其子树大小为\(siz[i]\),我们要给它的子树预定至少\(siz[i]\)个数。设\(f[i]\)表示第\(i\)个节点左边已经被预定的数的数量,那么\(i-f[i]\)即为第\(i\)个节点左边可用的数的数量。由于要为其子树预定至少\(siz[i]\)个数,我们需要找到一个位置\(x\),使得\(x\)右侧每个位置可用的数的数量都不小于\(siz[i]\),并把位置\(x\)上的数放到节点\(i\)上。如果位置\(x\)上的数不只出现一次,而是连续的一段,我们把最右边的那个放到节点\(i\)上。最后要把在选择的位置之后的所有位置的分\(f\)都加上\(siz[i]-1\)。

举个例子:9 8 7 6 5 5 5 5 5 4 3 2

假如第\(1\)个结点的子树大小为\(7\),那么第\(1\)个结点的值即为第\(7\)大的数:\(5\)

我们把最右边的\(5\)(第\(9\)位)给第\(1\)个结点

然后在 \([1,8]\) 这个区间内预定\(6\)个数给第\(1\)个结点的子树,于是\(F_9\cdots F_n\)都加上\(6\)

另外,在处理节点\(i\)时,如果它有父节点且父节点的预定值还没有撤销,要先撤销父节点预定的值。

用线段树去维护这一过程即可。

代码

#include<bits/stdc++.h>
#define MAXN 500010
#define lc rt<<1
#define rc rt<<1|1
using namespace std;
int fa[MAXN],t[MAXN<<2],tag[MAXN<<2],N,a[MAXN],siz[MAXN],num[MAXN],ans[MAXN];
double K;
bool vis[MAXN];
inline bool cmp(int a,int b){return a>b;}
inline void Up(int rt){t[rt]=min(t[lc],t[rc]);}
inline void Down(int rt){
    if(tag[rt]){
        t[lc]+=tag[rt];tag[lc]+=tag[rt];
        t[rc]+=tag[rt];tag[rc]+=tag[rt];
        tag[rt]=0;
    }
}
void Build(int l,int r,int rt){
    if(l==r){t[rt]=l;return;}
    int mid=l+r>>1;
    Build(l,mid,lc);Build(mid+1,r,rc);
    Up(rt);
}
void Add(int L,int R,int l,int r,int rt,int v){
    if(L<=l&&R>=r){t[rt]+=v;tag[rt]+=v;return;}
    int mid=l+r>>1;
    Down(rt);
    if(L<=mid)Add(L,R,l,mid,lc,v);
    if(R>mid)Add(L,R,mid+1,r,rc,v);
    Up(rt);
}
int Query(int l,int r,int rt,int v){
    if(l==r)return t[rt]>=v? l:l+1;
    int mid=l+r>>1;
    Down(rt);
    if(t[rc]>=v)return Query(l,mid,lc,v);
    else return Query(mid+1,r,rc,v);
}
int main(){
    #ifndef ONLINE_JUDGE
    freopen("iiidx.in","r",stdin);
    freopen("iiidx.out","w",stdout);
    #endif
    scanf("%d%lf",&N,&K);
    for(int i=1;i<=N;i++)scanf("%d",&a[i]),siz[i]=1;
    sort(a+1,a+1+N,cmp);
    for(int i=N-1;i>=1;i--)num[i]=a[i]==a[i+1]? num[i+1]+1:0;
    for(int i=1;i<=N;i++)fa[i]=floor(i/K);
    for(int i=N;i>=1;i--)siz[fa[i]]+=siz[i];
    Build(1,N,1);
    for(int i=1;i<=N;i++){
        if(fa[i]&&!vis[fa[i]]){Add(ans[fa[i]],N,1,N,1,siz[fa[i]]-1);vis[fa[i]]=1;}
        int x=Query(1,N,1,siz[i]);
        x=x+num[x];num[x]++;x-=(num[x]-1);ans[i]=x;
        Add(ans[i],N,1,N,1,-siz[i]);
    }
    for(int i=1;i<=N;i++)printf("%d%c",a[ans[i]],i==N?'\n':' ');
    return 0;
}

原文地址:https://www.cnblogs.com/lrj998244353/p/8797035.html

时间: 2024-08-11 19:25:45

5249: [2018多省省队联测]IIIDX的相关文章

bzoj 5249 [2018多省省队联测] IIIDX

bzoj 5249 [2018多省省队联测] IIIDX Link Solution 首先想到贪心,直接按照从大到小的顺序在后序遍历上一个个填 但是这样会有大问题,就是有相同的数的时候,会使答案不优 比如考虑 \((1, 2)(1, 3)(2, 4)\) 这样一棵树,并且点权是 \({1,1,1,2}\) 那么直接贪心会使得答案为 \(v_1=1,v_2=1,v_3=1,v_4=2\),但是实际上最优解为 \(v_1=1,v_2=1,v_3=2,v_4=1\) 问题出在我们先考虑 \(v_2\)

【刷题】BZOJ 5249 [2018多省省队联测]IIIDX

Description [题目背景] Osu听过没?那是Konano最喜欢的一款音乐游戏,而他的梦想就是有一天自己也能做个独特酷炫的音乐游戏.现在,他在世界知名游戏公司KONMAI内工作,离他的梦想也越来越近了.这款音乐游戏内一般都包含了许多歌曲,歌曲越多,玩家越不易玩腻.同时,为了使玩家在游戏上氪更多的金钱花更多的时间,游戏一开始一般都不会将所有曲目公开,有些曲目你需要通关某首特定歌曲才会解锁,而且越晚解锁的曲目难度越高. [题目描述] 这一天,Konano接到了一个任务,他需要给正在制作中的

bzoj5248: [2018多省省队联测]一双木棋

Description 菲菲和牛牛在一块n行m列的棋盘上下棋,菲菲执黑棋先手,牛牛执白棋后手.棋局开始时,棋盘上没有任何棋子, 两人轮流在格子上落子,直到填满棋盘时结束.落子的规则是:一个格子可以落子当且仅当这个格子内没有棋子且 这个格子的左侧及上方的所有格子内都有棋子. 棋盘的每个格子上,都写有两个非负整数,从上到下第i行中从左到右第j列的格子上的两个整数记作Aij.Bij.在 游戏结束后,菲菲和牛牛会分别计算自己的得分:菲菲的得分是所有有黑棋的格子上的Aij之和,牛牛的得分是所 有有白棋的格

bzoj5252 [2018多省省队联测]林克卡特树

斜率优化树形dp?? 我们先将问题转化成在树上选K+1条互不相交路径,使其权值和最大. 然后我们考虑60分的dp,直接维护每个点子树内选了几条路径,然后该点和0/1/2条路径相连 然后我们会发现最后的答案关于割的边数是一个单峰的函数,这时候事情就变得明朗起来个p 我们考虑拿一条斜率为k的直线去切这个函数,切到的点是什么?是每选一条路径额外付出k点代价时的最优解,于是我们二分这个斜率,然后直接树形dp求最优解以及位置即可,因为每次的最优解一定是上次的最优解和儿子的最优解共同转移而来的,所以我们只需

【刷题】BZOJ 5248 [2018多省省队联测]一双木棋

Description 菲菲和牛牛在一块n行m列的棋盘上下棋,菲菲执黑棋先手,牛牛执白棋后手.棋局开始时,棋盘上没有任何棋子, 两人轮流在格子上落子,直到填满棋盘时结束.落子的规则是:一个格子可以落子当且仅当这个格子内没有棋子且 这个格子的左侧及上方的所有格子内都有棋子. 棋盘的每个格子上,都写有两个非负整数,从上到下第i行中从左到右第j列的格子上的两个整数记作Aij.Bij.在 游戏结束后,菲菲和牛牛会分别计算自己的得分:菲菲的得分是所有有黑棋的格子上的Aij之和,牛牛的得分是所 有有白棋的格

bzoj千题计划307:bzoj5248: [2018多省省队联测]一双木棋

https://www.lydsy.com/JudgeOnline/problem.php?id=5248 先手希望先手得分减后手得分最大,后手希望先手得分减后手得分最小 棋盘的局面一定是阶梯状,且从上往下递减 可以将轮廓线作为状态,记忆化搜索 用n个数表示一个状态,第i个数表示第i行放了几个 记忆的状态表示当棋盘为这个状态时,接下来再下的最有解 记忆化搜索节省的是接下来再下的时间 #include<map> #include<cstdio> #include<cstring

BZOJ 5248: [2018多省省队联测]一双木棋

Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 439  Solved: 379[Submit][Status][Discuss] Description 菲菲和牛牛在一块n行m列的棋盘上下棋,菲菲执黑棋先手,牛牛执白棋后手.棋局开始时,棋盘上没有任何棋子, 两人轮流在格子上落子,直到填满棋盘时结束.落子的规则是:一个格子可以落子当且仅当这个格子内没有棋子且 这个格子的左侧及上方的所有格子内都有棋子. 棋盘的每个格子上,都写有两个非负整数,从上到下

bzoj 5496: [2019省队联测]字符串问题【SAM+拓扑】

有一个想法就是暴力建图,把每个A向有和他相连的B前缀的A,然后拓扑一下,这样的图是n^2的: 考虑优化建图,因为大部分数据结构都是处理后缀的,所以把串反过来,题目中要求的前缀B就变成了后缀B 建立SAM,发现在parent树中每个B能走到的A都在子树中,所以保留这个树结构,连边权为0的边: 然后在parent树上倍增找到每个AB串对应的点,因为SAM上每个对应不止一个串,所以找完之后把对应多个AB串的点拆成一条链 然后对于一对(x,y)的AB串关系,Ax对应的点向By对应的点连边权为A长度的边

bzoj 5498: [2019省队联测]皮配【dp】

是个神仙dp-- 参考:https://www.luogu.org/blog/xzz-233/solution-p5289 设f[i][j][k]是前i个有限制的城市,所有学校中选蓝色阵营有j人,有限制的学校中鸭派系有k人的方案数:g[i][j]是前i个没有限制的城市,蓝色阵营有j人的方案数:h[i][j]是前i个没有限制的学校,鸭派系有j人的方案数 f的转移枚举当前阵营 全dp出来之后,把gh前缀和处理,然后一段一段的和f合并加到ans上 #include<iostream> #includ