JZOJ 5405. 【NOIP2017提高A组模拟10.10】Permutation
来源:互联网 发布:centos debian 稳定性 编辑:程序博客网 时间:2024/06/04 21:48
Description
你有一个长度为n 的排列P 与一个正整数K
你可以进行如下操作若干次使得排列的字典序尽量小
对于两个满足|i-j|>=K 且|Pi-Pj| = 1 的下标i 与j,交换Pi 与Pj
Input
第一行包括两个正整数n 与K
第二行包括n 个正整数,第i 个正整数表示Pi
Output
输出一个新排列表示答案
输出共n 行,第i 行表示Pi
Sample Input
8 3
4 5 7 8 3 1 2 6
Sample Output
1
2
6
7
5
3
4
8
Data Constraint
对于前20% 的数据满足n <= 6
对于前50% 的数据满足n <= 2000
对于100% 的数据满足n <= 500000
Solution
读入
p[i] ,转化为:q[p[i]]=i ,q[i] 表示值为i 的位置在哪。考虑对于
q[i] 和q[j] ,若|q[i]−q[j]|<k (相距小于k ),则q[i] 和q[j] 始终不能互换位置。于是
q[i] 向q[j] (i>j) 连一条有向边即可,这样就构成了一个有向无环图。将入度为 0 的点加入一个小根堆,做一遍拓扑排序。
倒着枚举
i ,每次从堆里取出一个编号最小的x ,使
p[i]=x ,再将x 连出的点入度减一,为 0 则加入堆中。最后使
q[p[i]]=i , 再将q 输出即可。为什么要维护一个堆呢?因为如果两点连了边(不能位置互换),就不会同时存在于堆中。
在队中的点,肯定是可以位置互换的,那肯定是将小的数填在位置小那里,才能保证字典序最小。
-但是这种连边时间复杂度达到了
由于一个点只需与离它最近的点连边,维护一个维护最小值的线段树,
倒着枚举
i ,每次查询[q[i]−k+1,q[i]] 和[q[i],q[i]+k−1] 两个区间的最小值即距离最近的两个点(一大一小),连边后再将
q[i] 这个位置单点修改成编号i 即可。这样同样做一次拓扑排序,不会影响正确性,时间复杂度就成了
O(N log N) 。
Code
#include<cstdio>#include<cstring>#include<algorithm>#include<queue>using namespace std;const int N=5e5+1;int tot;int a[N],b[N],f[N<<2];int first[N],next[N<<2],en[N<<2],d[N];bool bz[N];priority_queue<int,vector<int>,less<int> >q;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<<3)+(X<<1)+ch-'0',ch=getchar(); return X*w;}inline void insert(int x,int y){ next[++tot]=first[x]; first[x]=tot; en[tot]=y; d[y]++;}inline void change(int v,int l,int r,int x,int y){ if(l==r) { f[v]=y; return; } int mid=(l+r)>>1; if(x<=mid) change(v<<1,l,mid,x,y); else change(v<<1|1,mid+1,r,x,y); f[v]=min(f[v<<1],f[v<<1|1]);}inline int find(int v,int l,int r,int x,int y){ if(x<=l && r<=y) return f[v]; int mid=(l+r)>>1; if(y<=mid) return find(v<<1,l,mid,x,y); if(x>mid) return find(v<<1|1,mid+1,r,x,y); return min(find(v<<1,l,mid,x,mid),find(v<<1|1,mid+1,r,mid+1,y));}int main(){ int n=read(),k=read(); for(int i=1;i<=n;i++) b[a[i]=read()]=i; memset(f,60,sizeof(f)); for(int i=n;i;i--) { int x=find(1,1,n,b[i]-k+1,b[i]); if(x<=n) insert(b[x],b[i]); x=find(1,1,n,b[i],b[i]+k-1); if(x<=n) insert(b[x],b[i]); change(1,1,n,b[i],i); } for(int i=1;i<=n;i++) if(!d[i]) q.push(i); for(int i=n;i;i--) { a[i]=q.top(); q.pop(); for(int j=first[a[i]];j;j=next[j]) if(!--d[en[j]]) q.push(en[j]); } for(int i=1;i<=n;i++) b[a[i]]=i; for(int i=1;i<=n;i++) printf("%d\n",b[i]); return 0;}
- JZOJ 5405.【NOIP2017提高A组模拟10.10】Permutation
- JZOJ 5405. 【NOIP2017提高A组模拟10.10】Permutation
- 【JZOJ 5405】【NOIP2017提高A组模拟10.10】Permutation
- 【NOIP2017提高A组模拟10.10】Permutation
- JZOJ 5406. 【NOIP2017提高A组模拟10.10】Tree
- JZOJ 5404. 【NOIP2017提高A组模拟10.10】Graph
- JZOJ 5404. 【NOIP2017提高A组模拟10.10】Graph
- [JZOJ5405]【NOIP2017提高A组模拟10.10】Permutation
- JZOJ5405. 【NOIP2017提高A组模拟10.10】Permutation
- 【jzoj5405】【NOIP2017提高A组模拟10.10】【Permutation】
- 【JZOJ 4931】【NOIP2017提高组模拟12.24】A
- 【JZOJ 4931】【NOIP2017提高组模拟12.24】A
- JZOJ 5195. 【NOIP2017提高组模拟7.3】A
- JZOJ 100026. 【NOIP2017提高A组模拟7.7】图
- JZOJ 100030. 【NOIP2017提高A组模拟7.8】为了爱情
- jzoj. 100031. 【NOIP2017提高A组模拟7.9】外星密码
- JZOJ 100035【NOIP2017提高A组模拟7.10】区间
- JZOJ 100036 【NOIP2017提高A组模拟7.10】随机
- 最新管家婆财贸双全.NET V17.0免狗破解
- 用java打包成jar可执行文件并执行windows定时任务
- 手动makecpb的方法
- Duplicate files copied in APK META-INF/
- Beautiful Soup的使用
- JZOJ 5405. 【NOIP2017提高A组模拟10.10】Permutation
- redis学习系列(三-1)--redis基础类型初探(字符串)
- Kafka架构和原理深度剖析
- ubuntu黑屏的原因
- Spring Boot的每个模块包详解
- cookie 和session 的区别详解
- 逆序输出
- Linux网络编程入门必备函数说明
- Maven学习