AT1984 Wide Swap

题意翻译

给出一个元素集合为\(\{1,2,\dots,N\}(1\leq N\leq 500,000)\)的排列\(P\),当有\(i,j(1\leq i<j\leq N)\)满足\(j-i\geq K\)\((1\leq K\leq N-1)\)且\(|P_{i}-P{j}|=1\)时,可以交换\(P_{i}\)和\(P_{j}\)

求:可能排列中字典序最小的排列

输入格式:

\(N\) \(K\)

\(P_{1}\) \(P_{2}\) \(\dots\) \(P_{N}\)


这题目真是好思路啊。

首先,一个元素有两个属性,称为权值\(p\)和位置\(l\),交换的过程可以定义为固定权值交换位置,或者固定位置交换权值。

发现原本题目中的条件不好操作,于是把权值和位置交换意义,那么问题就变成了:

让权值较小的尽可能呆在前面,当两个元素相邻并且权值之差不小于\(k\)时,可以交换这两个权值的位置。

我们把权值当成固有属性,拿位置去交换,那么如果两个元素的权值之差小于\(k\),那么它们的相对位置是不会改变的,我们对这一对按原有位置连一条有向边。

对整个图都这么连,然后以\(\tt{topo}\)序为第一关键字,权值为第二关键字跑优先队列\(\tt{topo}\)排序,就可以找到转换以后的字典序了。

但是发现这样连边是\(O(n^2)\)的,过不了这个题,得想办法优化一下连边。

考虑一个点\(i\)会向之后的哪些点连边,\(\tt{Ta}\)会连接权值在\([p_i-k+1,p_i+k-1]\)内的所有边,而\(k\)是不变的。所以我们只需要连接\(\tt{Ta}\)位置上第一个大于\(\tt{Ta}\)和第一个小于\(\tt{Ta}\)的边就可以了,其余的这两个点会连上。

发现可以用线段树维护,倒序加点,对权值建树,区间查询最小位置。

复杂度:\(O(nlogn)\)


Code:

#include <cstdio>
#include <cstring>
#include <queue>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define dep(i,a,b) for(int i=a;i>=b;i--)
#define lb(a) lower_bound(a)
#define is(a) insert(a)
#define ps(a) push(a)
const int N=5e5+10;
const int inf=0x3f3f3f3f;
int in[N],loc[N],p[N],ans[N],tot,n,k;
std::priority_queue <int,std::vector<int>,std::greater<int> > q;
int head[N],to[N<<1],Next[N<<1],cnt;
void add(int u,int v)
{
to[++cnt]=v,Next[cnt]=head[u],head[u]=cnt;
}
#define ls id<<1
#define rs id<<1|1
int min(int x,int y){return x<y?x:y;}
int max(int x,int y){return x>y?x:y;}
int mi[N<<2];
void change(int id,int l,int r,int p,int d)
{
if(l==r) {mi[id]=d;return;}
int mid=l+r>>1;
if(p<=mid) change(ls,l,mid,p,d);
else change(rs,mid+1,r,p,d);
mi[id]=min(mi[ls],mi[rs]);
}
int query(int id,int L,int R,int l,int r)
{
if(mi[id]==inf) return inf;
if(l==L&&r==R) return mi[id];
int Mid=L+R>>1;
if(r<=Mid) return query(ls,L,Mid,l,r);
else if(l>Mid) return query(rs,Mid+1,R,l,r);
else return min(query(ls,L,Mid,l,Mid),query(rs,Mid+1,R,Mid+1,r));
}
int main()
{
scanf("%d%d",&n,&k);
rep(i,1,n) scanf("%d",p),p[p[0]]=i;
memset(mi,0x3f,sizeof(mi));
dep(i,n,1)
{
int loc=query(1,1,n,p[i],min(n,p[i]+k-1));
if(loc!=inf) add(p[i],p[loc]),++in[p[loc]];
loc=query(1,1,n,max(1,p[i]-k+1),p[i]);
if(loc!=inf) add(p[i],p[loc]),++in[p[loc]];
change(1,1,n,p[i],i);
}
rep(i,1,n) if(!in[i]) q.ps(i);
while(!q.empty())
{
int now=q.top();
ans[now]=++tot;
q.pop();
for(int i=head[now];i;i=Next[i])
{
int v=to[i];
--in[v];
if(!in[v]) q.ps(v);
}
}
rep(i,1,n) printf("%d\n",ans[i]);
return 0;
}

2018.10.26

AT1984 Wide Swap的更多相关文章

  1. 【AtCoder Grand Contest 001F】Wide Swap [线段树][拓扑]

    Wide Swap Time Limit: 50 Sec  Memory Limit: 512 MB Description Input Output Sample Input 8 3 4 5 7 8 ...

  2. AtCoder AGC001F Wide Swap (线段树、拓扑排序)

    题目链接: https://atcoder.jp/contests/agc001/tasks/agc001_f 题解: 先变成排列的逆,要求\(1\)的位置最小,其次\(2\)的位置最小,依次排下去( ...

  3. AGC001F - Wide Swap

    Description 给你一个长度为$n$的排列,每次可以交换$|i-j|\geq K$并且$|a_i-a_j|=1$的数对,问你经过若干次变换后最小字典序的排列是啥 Solution 对$a$做一 ...

  4. AGC001 F - Wide Swap【线段树+堆+拓扑排序】

    给出的模型很难搞,所以转换一下,记p[i]为i这个数的位置,然后相邻两个p值差>k的能交换,发现使原问题字典序最小也需要使这里的字典序最小 注意到p值差<=k的前后顺序一定不変,那么可以n ...

  5. AtCoder Grand Contest 001F Wide Swap

    解法参考这位大佬的:https://www.cnblogs.com/BearChild/p/7895719.html 因为原来的数组不好做于是我们想反过来数组,根据交换条件:值相邻且位置差大于等于k, ...

  6. 题解 Wide Swap

    题目传送门 题目大意 给出一个长度为 \(n\) 的排列 \(a_{1,2,...,n}\) 以及常数 \(k\),每次可以交换两个数 \(a_i,a_j\) 当且仅当 \(j-i\ge k \tex ...

  7. [atAGC001F]Wide Swap

    结论:排列$p'_{i}$可以通过排列$p_{i}$得到当且仅当$\forall 1\le i<j<i+k,(p_{i}-p_{j})(p'_{i}-p'_{j})>0$ 证明:构造 ...

  8. Atcoder Grand Contest 001 F - Wide Swap(拓扑排序)

    Atcoder 题面传送门 & 洛谷题面传送门 咦?鸽子 tzc 来补题解了?奇迹奇迹( 首先考虑什么样的排列可以得到.我们考虑 \(p\) 的逆排列 \(q\),那么每次操作的过程从逆排列的 ...

  9. RE:从零开始的AGC被虐(到)生活(不能自理)

    RE:从零开始的AGC被虐(到)生活(不能自理) 「一直注视着你,似近似远,总是触碰不到.」 --来自风平浪静的明天 AtCoder Grand Contest 001 B: Mysterious L ...

随机推荐

  1. andriod 学习三 使用android资源

    3.1 android框架中有许多资源,包括布局,字符串,位图,图片....,使用资源之前需要在相应的资源文件中定义资源,然后编译程序时ADT将定义的资源转换成java类并给予唯一的id,而代码中需要 ...

  2. ansible基础配置使用(一)

    test  test  test

  3. 第六模块:WEB框架开发 第1章·Django框架开发50~87

    51-表关系之一对多 52-表关系之多对多 53-表关系之一对一 54-数据库表关系之关联字段与外键约束 55-数据库表关系之sql创建关联表 56-ORM生成关联表模型 57-多表操作之一对多添加记 ...

  4. Linux搭建mysql、apache、php服务总结

    本随笔文章,由个人博客(鸟不拉屎)转移至博客园 写于:2018 年 04 月 22 日 原地址:https://niaobulashi.com/archives/linux-mysql-apache- ...

  5. Nginx与Ribbon的区别

    服务器端负载均衡 Nginx Nginx 基于C语言,快速,性能高5w/s. Redis 5w/s,RibbatMQ 1.2w/s ApacheActiveMQ 0.6w/s 业务系统,kafka 2 ...

  6. 骰子涂色 (Cube painting,UVa 253)

    题目描述:算法竞赛入门习题4-4  题目思路:1.旋转其中一个骰子进行匹配 2.进行遍历,如果匹配,就进行相对面的匹配 3.三个对立面都匹配即是一样等价的 //没有按照原题的输入输出 #include ...

  7. CMD Markdown basic & Math Cheatsheet

    CMD Markdown basic & Math Cheatsheet I am using CMD Markdown both at work and for study.You can ...

  8. js经典试题之ES6

    js经典试题之ES6 1:在ECMAScript6 中,Promise的状态 答案:pending  resolved(fulfilled) rejected 解析: Promise对象只有三种状态: ...

  9. Android屏幕适配解析 - 详解像素,设备独立像素,归一化密度,精确密度及各种资源对应的尺寸密度分辨率适配问题

    . 作者 :万境绝尘 转载请注明出处 : http://blog.csdn.net/shulianghan/article/details/19698511 . 最近遇到了一系列的屏幕适配问题, 以及 ...

  10. Calculator PartⅢ

    GitHub/object-oriented The title of the work 这次敲代码耗时相对较短,但是始终无法完成debug步骤,目前上传的代码可以通过编译,但运行即报停,问题调试为内 ...