bzoj 5249 [2018多省省队联测]IIIDX
Description
【题目背景】
Osu听过没?那是Konano最喜欢的一款音乐游戏,而他的梦想就是有一天自己也能做个独特酷炫的音乐游戏。现在
,他在世界知名游戏公司KONMAI内工作,离他的梦想也越来越近了。这款音乐游戏内一般都包含了许多歌曲,歌曲
越多,玩家越不易玩腻。同时,为了使玩家在游戏上氪更多的金钱花更多的时间,游戏一开始一般都不会将所有曲
目公开,有些曲目你需要通关某首特定歌曲才会解锁,而且越晚解锁的曲目难度越高。
【题目描述】
这一天,Konano接到了一个任务,他需要给正在制作中的游戏《IIIDX》安排曲目的解锁顺序。游戏内共有n首曲目
,每首曲目都会有一个难度d,游戏内第i首曲目会在玩家Pass第trunc(i/k)首曲目后解锁(x为下取整符号)若tru
nc(i/k)=0,则说明这首曲目无需解锁。举个例子:当k=2时,第1首曲目是无需解锁的(trunc(1/2)=0),第7首曲
目需要玩家Pass第trunc(7/2)=3首曲目才会被解锁。Konano的工作,便是安排这些曲目的顺序,使得每次解锁出的
曲子的难度不低于作为条件需要玩家通关的曲子的难度,即使得确定顺序后的曲目的难度对于每个i满足Di≥Dtrun
c(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
114 514 1919 810
Sample Output
114 810 514 1919
贪心写挂了一分都没有
正解好像还是挺好写的
先sort一下
用线段树维护比第i个点大的还没有被用到的数的个数f[i]
每次选择最大的一个d[i]使得f[i]~f[n]都大于当前子树的大小
然后f[i]~f[n]都减去这个子树的大小
有点小细节
每次枚举到一个点的时候需要把它对他父亲的限制的贡献减去
有相同的a[i]要选最右边的那个
想清楚了就很好码了
//%std #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<string> #include<algorithm> #include<cmath> #include<vector> #include<queue> #include<stack> #include<set> #include<map> using namespace std; #define lovelive long long #define lc son[x][0] #define rc son[x][1] #define lowbit(x) (x&(-x)) #define pt vc const int N=5e5+100; void read(int &x) { int p=1; x=0; char c=getchar(); while(c<'0'||c>'9') { if(c=='-') p=-1; c=getchar(); } while(c>='0'&&c<='9') { x=x*10+c-48; c=getchar(); } x*=p; } struct tree{ int l,r; int sum,lazy; }t[N*4]; void buildtree(int i,int l,int r) { t[i].l=l; t[i].r=r; if(l==r) { t[i].sum=l; return; } int mid=(l+r)>>1; buildtree(i<<1,l,mid); buildtree(i<<1|1,mid+1,r); t[i].sum=min(t[i<<1].sum,t[i<<1|1].sum); } void pushdown(int i) { if(!t[i].lazy) return; t[i<<1].sum+=t[i].lazy; t[i<<1|1].sum+=t[i].lazy; t[i<<1].lazy+=t[i].lazy; t[i<<1|1].lazy+=t[i].lazy; t[i].lazy=0; } void change(int i,int l,int r,int x) { if(l>t[i].r||r<t[i].l) return; if(l<=t[i].l&&t[i].r<=r) { t[i].sum+=x;; t[i].lazy+=x; return; } pushdown(i); change(i<<1,l,r,x); change(i<<1|1,l,r,x); t[i].sum=min(t[i<<1].sum,t[i<<1|1].sum); } int find(int x) { int i=1,r; if(t[i].sum>=x) return 1; while(1) { if(t[i].l==t[i].r) break; pushdown(i); if(t[i<<1|1].sum>=x) r=t[i<<1|1].l,i=i<<1; else i=i<<1|1; } return r; } int d[N],ans[N],fa[N],siz[N]; int nxt[N]; int main() { int n,x; double k; // freopen("iiidx.in","r",stdin); // freopen("iiidx.out","w",stdout); read(n);scanf("%lf",&k); for(int i=1;i<=n;i++) fa[i]=floor(i/k+1e-10); for(int i=n;i>=1;i--) siz[fa[i]]+=++siz[i]; for(int i=1;i<=n;i++) read(d[i]); sort(d+1,d+n+1); for(int i=1;i<=n;i++) if(i<n-i+1) swap(d[i],d[n-i+1]); nxt[n]=n; for(int i=n-1;i>=1;i--) if(d[i+1]==d[i]) nxt[i]=nxt[i+1]; else nxt[i]=i; buildtree(1,1,n); for(int i=1;i<=n;i++) { if(fa[i]) change(1,ans[fa[i]],n,siz[i]); x=find(siz[i]); x=nxt[x]; ans[i]=x; change(1,x,n,-siz[i]); } for(int i=1;i<=n;i++) cout<<d[ans[i]]<<" "; return 0; }