[JZOJ5405]【NOIP2017提高A组模拟10.10】Permutation
来源:互联网 发布:js上传图片并预览 编辑:程序博客网 时间:2024/06/04 17:41
Description
你有一个长度为n 的排列P 与一个正整数K
你可以进行如下操作若干次使得排列的字典序尽量小
对于两个满足|i-j|>=K 且|Pi-Pj| = 1 的下标i 与j,交换Pi 与Pj对于100% 的数据满足n <= 500000
Solution
隔着K个数之间交换比较麻烦,不如变换一下题意
原序列记录每个位置上的数什么
不妨新开一个数组Q记录每个数在哪个位置。
交换只是相邻两个交换,只要相邻两个数的差的绝对值大于等于K就可以交换。
排列P的字典序最小,与数组Q的字典序最小是等价的。
有了这个结论,就可以直接在数组Q上做了。
下面的值都是数组Q上的值
显然,如果
那么就有了一种
最小字典序的拓扑序可以维护一个堆,每次取堆顶加入拓扑序,扩展节点,新走出的节点入度为0时加入堆即可。
然而可以发现,这样连边会有大量不必要的边。
对于
如果
那么只需要Q[x]连Q[y],Q[y]连Q[z]即可。
那么从后往前扫,对于当前扫到的Q[i],只需要找到i后面最小的x,y,使得
Q[i]分别向
这个东西可以维护一个权值线段树,从后向前扫的时候插入即可。
Code
#include <cstdio>#include <algorithm>#include <cstring>#include <cmath>#include <iostream>#include <cstdlib>#include <queue>#define fo(i,a,b) for(int i=a;i<=b;i++)#define fod(i,a,b) for(int i=a;i>=b;i--)#define N 500005#define INF 2147483647using namespace std;int n,w[N],m,m1,n1,fs[N],nt[2*N],dt[2*N],rd[N],d[N],as[N],a1[N];priority_queue <int> a;void link(int x,int y){ nt[++m1]=fs[x]; rd[dt[fs[x]=m1]=y]++;}struct node{ int s,l,r,s1;}tr[5*N];void up(int k){ tr[k].s=min(tr[tr[k].l].s,tr[tr[k].r].s); tr[k].s1=max(tr[tr[k].l].s1,tr[tr[k].r].s1);}void ins(int k,int l,int r,int x,int v){ if(l==r) tr[k].s=v,tr[k].s1=v; else { int mid=(l+r)/2; if(!tr[k].l) tr[k].l=++n1,tr[n1].s=INF; if(!tr[k].r) tr[k].r=++n1,tr[n1].s=INF; if(x<=mid) ins(tr[k].l,l,mid,x,v); else ins(tr[k].r,mid+1,r,x,v); up(k); }}int fd(int k,int l,int r,int x,int y){ x=max(x,l),y=min(y,r); if(x>y||k==0) return INF; if(l==x&&r==y) return tr[k].s; int mid=(l+r)/2; return min(fd(tr[k].l,l,mid,x,y),fd(tr[k].r,mid+1,r,x,y));}int fd2(int k,int l,int r,int x,int y){ x=max(x,l),y=min(y,r); if(x>y||k==0) return 0; if(l==x&&r==y) return tr[k].s1; int mid=(l+r)/2; return max(fd2(tr[k].l,l,mid,x,y),fd2(tr[k].r,mid+1,r,x,y));}void doit(){ int l=0,r=d[0]; fo(i,1,n) if(rd[i]==0) a.push(-i); while(r<n) { int k=-a.top(); a.pop(); d[++r]=k; for(int i=fs[k];i;i=nt[i]) { int p=dt[i]; rd[p]--; if(rd[p]==0) a.push(-p); } }}int main(){ cin>>n>>m; n1=1; fo(i,1,n) { scanf("%d",&a1[i]); w[a1[i]]=i; } ins(1,1,n,w[n],n); fod(i,n-1,1) { int p=fd(1,1,n,w[i],w[i]+m-1),q=fd(1,1,n,w[i]-m+1,w[i]); if(p!=INF) link(w[i],w[p]); if(q!=INF) link(w[i],w[q]); ins(1,1,n,w[i],i); } doit(); fo(i,1,n) as[d[i]]=i; fo(i,1,n) printf("%d\n",as[i]);}
- [JZOJ5405]【NOIP2017提高A组模拟10.10】Permutation
- JZOJ5405. 【NOIP2017提高A组模拟10.10】Permutation
- 【jzoj5405】【NOIP2017提高A组模拟10.10】【Permutation】
- 【NOIP2017提高A组模拟10.10】Permutation
- 【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】总结
- 【NOIP2017提高A组模拟10.10】Graph
- JZOJ 5406. 【NOIP2017提高A组模拟10.10】Tree
- JZOJ 5404. 【NOIP2017提高A组模拟10.10】Graph
- JZOJ 5404. 【NOIP2017提高A组模拟10.10】Graph
- [jzoj5406]【NOIP2017提高A组模拟10.10】Tree
- 5404. 【NOIP2017提高A组模拟10.10】Graph
- A【NOIP2017提高组模拟12.18】
- 【JZOJ4928】【NOIP2017提高组模拟12.18】A
- 【NOIP2017提高组模拟12.18】A
- 【JZOJ4928】【NOIP2017提高组模拟12.18】A
- 面试记录第十五节——(bitmap释放、lru、三级缓存、图片压缩)
- IOS -- 获取用户的健康数据的运动步数
- krpano360全景教程
- Linux 安装Anaconda
- toString()与new String ()用法区别
- [JZOJ5405]【NOIP2017提高A组模拟10.10】Permutation
- 课堂练习二
- Android基础—四大组件之Activity
- 工厂三兄弟之工厂方法模式(四)
- 百度搜索框
- Java+Selenium3.0利用geckodirver启动firefox for Mac
- video.js API 详解
- JavaScript HTML DOM 事件
- 服务端安装svn