BZOJ5249:[九省联考2018]IIIDX——题解
https://www.luogu.org/problemnew/show/P4364#sub
https://www.lydsy.com/JudgeOnline/problem.php?id=5249
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)。
智商好题。
当时在考场上就写的55分贪心,之后也举出过反例证明无法贪掉d有重复的点,结果凉凉。
但其实和贪心差不多,我们先对d从大到小排序,则对于每个靠前的点来说,它在合法态下尽可能取最靠左的d,而当d相同时它尽可能靠右。
这个位置可以用二分得到,至于合法就用线段树维护当前点左边还可以取多少点即可。
PS:bzoj卡精度。
#include<cstdio> #include<cmath> #include<vector> #include<iostream> #include<stack> #include<cstring> #include<algorithm> #include<cctype> using namespace std; typedef double dl; const int N=5e5+5; const int INF=1e9; const dl eps=1e-8; inline int read(){ int x=0,w=1;char ch=0; while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} return x*w; } int n,d[N],tr[N*4],lz[N*4],cnt[N],size[N],fa[N],ans[N]; dl k; inline bool cmp(int a,int b){return a>b;} inline void upt(int a){tr[a]=min(tr[a<<1],tr[a<<1|1]);} inline void push(int a){ if(!lz[a])return; lz[a<<1]+=lz[a];lz[a<<1|1]+=lz[a]; tr[a<<1]+=lz[a];tr[a<<1|1]+=lz[a]; lz[a]=0; } void build(int a,int l,int r){ if(l==r){ tr[a]=l; return; } int mid=(l+r)>>1; build(a<<1,l,mid);build(a<<1|1,mid+1,r); upt(a); } void mdy(int a,int l,int r,int l1,int r1,int w){ if(r<l1||r1<l)return; if(l1<=l&&r<=r1){ tr[a]+=w;lz[a]+=w; return; } push(a); int mid=(l+r)>>1; mdy(a<<1,l,mid,l1,r1,w);mdy(a<<1|1,mid+1,r,l1,r1,w); upt(a); } int query(int a,int l,int r,int x){ if(l==r)return tr[a]>=x?l:l+1; push(a); int mid=(l+r)>>1; if(x>tr[a<<1|1])return query(a<<1|1,mid+1,r,x); return query(a<<1,l,mid,x); } int main(){ scanf("%d%lf",&n,&k); for(int i=1;i<=n;i++)d[i]=read(); sort(d+1,d+n+1,cmp); for(int i=n;i>=1;i--){ if(d[i]==d[i+1])cnt[i]=cnt[i+1]+1; else cnt[i]=0; fa[i]=(int)((dl)i/k+eps);size[i]++; size[fa[i]]+=size[i]; } build(1,1,n); for(int i=1;i<=n;i++){ if(fa[i]&&fa[i]!=fa[i-1]){ mdy(1,1,n,ans[fa[i]],n,size[fa[i]]-1); } int x=query(1,1,n,size[i]); int t=x;x+=cnt[x];cnt[t]--; ans[i]=x; mdy(1,1,n,ans[i],n,-size[i]); } for(int i=1;i<=n;i++)printf("%d ",d[ans[i]]); puts(""); return 0; }
+++++++++++++++++++++++++++++++++++++++++++
+本文作者:luyouqi233。 +
+欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/ +
+++++++++++++++++++++++++++++++++++++++++++