JZOJ 5405.【NOIP2017提高A组模拟10.10】Permutation
来源:互联网 发布:北京外语网络教育官网 编辑:程序博客网 时间:2024/05/16 06:26
题目
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
对于100% 的数据满足n <= 500000
题解
在比赛的过程中,我发现p[i]变成x,当前仅当条件:x和p[i]之间的所有数,p[i]都与他们距离≥k。
为了方便解决此题,我们将问题转化为:q[p[i]]=i,然后对q序列解决问题。那么两个数能移动,当且仅当相邻且
所以,我们只要找到与i相关的两个数j1,j2>i,
表示j1无论怎么只靠跟后面换,都不能够换到i前面(若j1可以跟前面换则不优)。j2同理
即表示,最后i表示的数在j1,j2前面。
这样子我们搞出了一个DAG。
由于题目要求输出最小字典序的序列,所以保证拓扑序字典序最小即可。
解决方案:用优先队列存储即可,每次让最小的出队就行了。
然而C++的priority_queue默认为“大根堆”。“小根堆”怎么办?
解决方案:将加进优先队列的数取相反数,然后取出来的时候再去相反数。
对这道题目的心得:
①不要将数列上的数看得太死,要让他们在脑中”动起来”。
②一道题目这么难,肯定有突破口,比如这题的一定交换相邻的两个数,这两个数绝对值等于1!!!所以可以想到一直交换,直到有一个交换不到的数就截止。
③最重要的一点,对于这种序列(这种序列是排列)的问题,如果涉及到要利用”每个数的位置”来解决问题,就可以试下考虑逆数组。即q[p[i]]=i。
代码
#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>#include<queue>#define N 500010#define fo(i,a,b) for(i=a;i<=b;i++)#define fd(i,a,b) for(i=a;i>=b;i--)using namespace std;struct note{ int to,next;};note edge[N*2];int p[N],q[N];int tr[N*20],ru[N];int i,j,k,L,R,l,r,n,temp,now,ans,step;int tot,head[N];priority_queue<int>qu;bool pp;void read(int &n){ n=0;char ch=getchar(); while((ch<'0' || ch>'9') && ch!='-')ch=getchar(); int w=1; if(ch=='-')w=-1,ch=getchar(); while('0'<=ch && ch<='9')n=n*10+ch-'0',ch=getchar(); n*=w;}void write(int x){ if(x>9)write(x/10); putchar(x%10+'0');}void lb(int x,int y){ edge[++tot].to=y; edge[tot].next=head[x]; head[x]=tot; ru[y]++;}void update(int ps){ tr[ps]=min(tr[ps*2],tr[ps*2+1]);}void change(int ps,int l,int r,int x,int z){ if(l==r){ tr[ps]=z; return; } int wz=(l+r)/2; if(x<=wz)change(ps*2,l,wz,x,z); else change(ps*2+1,wz+1,r,x,z); update(ps);}void find(int ps,int l,int r,int x,int y){ if(l==x && r==y){ temp=min(temp,tr[ps]); return; } int wz=(l+r)/2; if(y<=wz)find(ps*2,l,wz,x,y);else if(x>wz)find(ps*2+1,wz+1,r,x,y);else{ find(ps*2,l,wz,x,wz); find(ps*2+1,wz+1,r,wz+1,y); } }int main(){ freopen("permutation.in","r",stdin); freopen("permutation.out","w",stdout); read(n),read(k); fo(i,1,n)read(p[i]),q[p[i]]=i; memset(tr,127,sizeof(tr)); fd(i,n,1){ L=max(1,q[i]-k+1);R=q[i];temp=n+1; find(1,1,n,L,R); if(temp<=n)lb(q[i],q[temp]); L=q[i];R=min(n,q[i]+k-1);temp=n+1; find(1,1,n,L,R); if(temp<=n)lb(q[i],q[temp]); change(1,1,n,q[i],i); } fo(i,1,n)if(!ru[i]) qu.push(-i); memset(q,0,sizeof(q)); fo(i,1,n){ int now=qu.top(); now=-now; q[i]=now; qu.pop(); for(j=head[now];j;j=edge[j].next){ ru[edge[j].to]--; if(!ru[edge[j].to])qu.push(-edge[j].to); } } fo(i,1,n)p[q[i]]=i; fo(i,1,n)write(p[i]),putchar('\n'); 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】随机
- man命令
- sklearn pipeline
- 服务器推送数据之Comet
- 【Lightoj 1063
- java对象初始化顺序(含测试代码)
- JZOJ 5405.【NOIP2017提高A组模拟10.10】Permutation
- 04-树4 是否同一棵二叉搜索树(25 分)
- 移位操作符.位操作符,sizeof
- 内存对齐(Struct)
- 关于IAR go to Definition功能不能使用的解决方法
- Lucene 7.0测试使用
- Oracle (内连接)与(外连接)区别
- vim文本对象
- 计算可能的编译结果数