Osu 听过没?那是 Konano 最喜欢的一款音乐游戏,而他的梦想就是有一天自己也能做个独特酷炫的音乐游戏。现在,他在世界知名游戏公司 KONMAI 内工作,离他的梦想也越来越近了。
这款音乐游戏内一般都包含了许多歌曲,歌曲越多,玩家越不易玩腻。同时,为了使玩家在游戏上氪更多的金钱花更多的时间,游戏一开始一般都不会将所有曲目公开,有些曲目你需要通关某首特定歌曲才会解锁,而且越晚解锁的曲目难度越高。
这一天,Konano 接到了一个任务,他需要给正在制作中的游戏《IIIDX》安排曲目的解锁顺序。游戏内共有 n n 首曲目,每首曲目都会有一个难度 d d ,游戏内第 i i 首曲目会在玩家 Pass 第 ⌊ik⌋ ⌊ i k ⌋ 首曲目后解锁( ⌊x⌋ ⌊ x ⌋ 为下取整符号)若 ⌊ik⌋=0 ⌊ i k ⌋ = 0 ,则说明这首曲目无需解锁。
举个例子:当 k=2 k = 2 时,第 1 1 首曲目是无需解锁的( ⌊12⌋=0 ⌊ 1 2 ⌋ = 0 ),第 7 7 首曲目需要玩家 Pass 第 ⌊72⌋=3 ⌊ 7 2 ⌋ = 3 首曲目才会被解锁。
Konano 的工作,便是安排这些曲目的顺序,使得每次解锁出的曲子的难度不低于作为条件需要玩家通关的曲子的难度,即使得确定顺序后的曲目的难度对于每个 i i 满足 di≥d⌊ik⌋ d i ≥ d ⌊ i k ⌋ 。
当然这难不倒曾经在信息学竞赛摸鱼许久的 Konano。那假如是你,你会怎么解决这份任务呢?
测试点编号 | n n | k k | d d | 特殊限制 |
---|---|---|---|---|
1 1 | 1≤n≤10 1 ≤ n ≤ 10 | k=2 k = 2 | 1≤d≤100 1 ≤ d ≤ 100 | 保证 di d i 互不相同 |
2 2 | k=3 k = 3 | |||
3 3 | k=1.1 k = 1.1 | |||
4 4 | k=n k = n | |||
5 5 | 1<k≤100 1 < k ≤ 100 | |||
6 6 | ||||
7 7 | 1≤n≤2000 1 ≤ n ≤ 2000 | k=2 k = 2 | 1≤d≤109 1 ≤ d ≤ 10 9 | 保证 di d i 互不相同 |
8 8 | 无 | |||
9 9 | k=3 k = 3 | 保证 di d i 互不相同 | ||
10 10 | 无 | |||
11 11 | 1<k≤109 1 < k ≤ 10 9 | 保证 di d i 互不相同 | ||
12 12 | 无 | |||
13 13 | 1≤n≤500000 1 ≤ n ≤ 500000 | k=2 k = 2 | ||
14 14 | k=3 k = 3 | |||
15 15 | 1<k≤109 1 < k ≤ 10 9 | 保证 di d i 互不相同 | ||
16 16 | ||||
17 17 | 无 | |||
18 18 | ||||
19 19 | ||||
20 20 |
首先考虑部分分的做法。
很显然可以发现,本题对于歌曲解锁的顺序限制是一个树形的结构,这样一来,题目的要求就可以变成把一堆数放到一颗树上,使得儿子均比父亲来得大,并且要求解最大。
贪心地来想,好像按树的后序遍历从大到小放数字就是最优解了。
然而 ⋯ ⋯ ,如果数有相同,那么就会出现一些不对的情况。
假设我们的序列是这样
也可以换一种理解方式,就是我们每次贪心地选一个数以后,都要保证预留一些树来放在这个点的子树中,于是我们就一步步做然后保证不矛盾就行了。接着在这个基础上使得解最大。
于是我们开一颗线段树,就能维护上面那些区间修改和查询了。
其实线段树只需要直接维护 i−fi i − f i 就行了。
(我才不会说我从小到大排序是因为不想用 greater greater 的)
#include
using namespace std;
#define R register
const int maxn = 5e5+10;
struct Edge{
int To;
Edge *Next;
}*Head[maxn];
inline void Add(R int u,R int v){
static Edge E[maxn],*e=E;
*e=(Edge){v,Head[u]};Head[u]=e++;
}
int n,d[maxn],*c=d;
double k;
int fa[maxn];
int Ans[maxn];
void dfs(R int u){
for(R Edge *i=Head[u];i;i=i->Next){
dfs(i->To);
}
if(u)Ans[u]=*++c;
}
int main(){
scanf("%d %lf",&n,&k);
for(R int i=1;i<=n;++i)scanf("%d",d+i);
sort(d+1,d+1+n,greater<int>());
for(R int i=n;i;i--){
fa[i]=(int)(1.0*i/k);
Add(fa[i],i);
}
dfs(0);
for(R int i=1;i<=n;++i)printf("%d ",Ans[i]);
return 0;
}
#include
#define R register
#define LL long long
template<class TT>inline TT Max(R TT a,R TT b){return atemplate<class TT>inline TT Min(R TT a,R TT b){return ausing namespace std;
template<class TT>inline void read(R TT &x){
x=0;R bool f=false;R char c=getchar();
for(;c<48||c>57;c=getchar())f|=(c=='-');
for(;c>47&&c<58;c=getchar())x=(x<<1)+(x<<3)+(c^48);
(f)&&(x=-x);
}
int happy;
const int maxn = 1000010;
int n,d[maxn];
double k;
//Graph
int tp;
struct Edge{
int to;
Edge *next;
}*head[maxn];
inline void Add(R int u,R int v){
static Edge E[maxn],*e=E;
*e=(Edge){v,head[u]};head[u]=e++;
}
//end
//segment_tree
#define Ls (i<<1)
#define Rs (i<<1|1)
int s[1<<20],t[1<<20];
inline void push_down(R int i){
if(t[i]){
R int x=t[i];
t[Ls]+=x;
t[Rs]+=x;
s[Ls]+=x;
s[Rs]+=x;
t[i]=0;
}
}
#define defvar R int l,R int r,R int i
void build(defvar){
if(l==r){s[i]=n-l+1;return;}
R int mid=l+r>>1;
build(l,mid,Ls);
build(mid+1,r,Rs);
s[i]=Min(s[Ls],s[Rs]);
}
void add(defvar,R int ql,R int qr,R int qx){
if(ql<=l&&r<=qr){
s[i]+=qx;
t[i]+=qx;
return;
}
push_down(i);
R int mid=l+r>>1;
if(ql<=mid)add(l,mid,Ls,ql,qr,qx);
if(qr>mid)add(mid+1,r,Rs,ql,qr,qx);
s[i]=Min(s[Ls],s[Rs]);
}
int query(defvar,R int qp,R int qx){
R int mid=l+r>>1,x=0;
if(qp<=l){
if(s[i]>=qx)return 0;
if(l==r)return l-1;
push_down(i);
if(s[Ls]>=qx){
x=query(mid+1,r,Rs,qp,qx);
s[i]=Min(s[Ls],s[Rs]);
return x;
}
if(s[Ls]if(x)return x;
}
return l-1;
}
push_down(i);
if(qp<=mid)x=query(l,mid,Ls,qp,qx);
if(!x)x=query(mid+1,r,Rs,qp,qx);
s[i]=Min(s[Ls],s[Rs]);
return x;
}
//end
//get size
int siz[maxn];
void dfs(R int u){
siz[u]=1;
for(R Edge *i=head[u];i;i=i->next){
dfs(i->to);
siz[u]+=siz[i->to];
}
}
//end
int fa[maxn];
int st[maxn],pos[maxn],lth[maxn];
int main(){
read(n);
happy=scanf("%lf",&k);
for(R int i=1;i<=n;++i)read(d[i]);
for(R int i=1;i<=n;++i){
fa[i]=1.0*i/k;
Add(fa[i],i);
}
dfs(0);
sort(d+1,d+1+n);
build(1,n,1);
for(R int i=1;i<=n;++i){
if(d[i]!=d[i-1])st[i]=i;
else st[i]=st[i-1];
}
for(R int i=1,p;i<=n;++i){
p=query(1,n,1,pos[fa[i]]+1,siz[i]);
if(!p)p=n-siz[i]+1;
p=st[p]+lth[st[p]];
printf("%d ",d[p]);
lth[st[p]]++;
pos[i]=p;
add(1,n,1,pos[fa[i]]+1,p,-siz[i]);
}
return 0;
}