【题解】AT1984 Wide Swap(拓扑排序)

【题解】AT1984 Wide Swap(拓扑排序)

排列问题的一大套路是考虑arc数组(arc[data[t]]=t)

然后题目那个swap的性质,就转换为了对于arc数组相邻的值,若其差大于等于\(k\)则可以交换,否则不能。

考虑arc数组上任意两个数\(x,y\)(假设x的位置<y的位置)能够交换的条件,条件就是在\(x,y\)之间不存在和他们的差小于\(k\)的数。但如果有的话,那么\(x,y\)永远也不能交换了。也就是说,最终答案中,位置为\(x\)的数一定会小于位置\(y\)的数。

"一定小于"关系会形成一个DAG,规定若\(y->x\)表示\(x\)位置上的数一定要比y的小。满足这个DAG的所有方案都是合法方案。一个生成合法方案的算法是在这个DAG上按拓扑一个个剥点,并且剥点时要分配递增的标号,这就相当于得到一个拓扑序,并且使得第\(1\)小的点尽量靠前,然后再满足第二大的尽量靠前...这就变成了HNOI菜肴制作了。

考虑复杂度的问题,暴力\(O(n^2)\)枚举不行的,可以发现若\(x,y\)不能交换且\(y,z\)不能交换,那么\(x,z\)不能交换(z的位置大于y的位置),所以只要连接一下那个下标最小的y就行了。

//@winlere
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>

using namespace std;  typedef long long ll;
inline int qr(){
    int ret=0,f=0,c=getchar();
    while(!isdigit(c))f|=c==45,c=getchar();
    while(isdigit(c)) ret=ret*10+c-48,c=getchar();
    return f?-ret:ret;
}

const int maxn=5e5+5;
const int inf=0x3f3f3f3f;
vector<int> e[maxn];
int data[maxn],arc[maxn],dr[maxn],n,k;
int seg[maxn<<2],ans[maxn];
void pp(int pos){seg[pos]=min(seg[pos<<1],seg[pos<<1|1]);}
void add(int fr,int to){e[to].push_back(fr);++dr[fr];}

#define mid ((l+r)>>1)
#define lef l,mid,pos<<1
#define rgt mid+1,r,pos<<1|1
int que(int L,int R,int l,int r,int pos){
    if(L>r||R<l) return inf;
    if(L<=l&&r<=R) return seg[pos];
    return min(que(L,R,lef),que(L,R,rgt));
}
void upd(int p,int v,int l,int r,int pos){
    if(p<l||p>r) return;
    if(l==r) return seg[pos]=v,void();
    upd(p,v,lef); upd(p,v,rgt);
    pp(pos);
}
#undef mid
#undef lef
#undef rgt

int main(){
    n=qr(); k=qr();
    for(int t=1;t<=n;++t) data[t]=qr(),arc[data[t]]=t;
    memset(seg,0x3f,sizeof seg);
    for(int t=n;t;--t){
        int t1=que(arc[t]-k+1,arc[t]-1,1,n,1);
        int t2=que(arc[t]+1,arc[t]+k-1,1,n,1);
        if(t1<=n) add(arc[t],arc[t1]);
        if(t2<=n) add(arc[t],arc[t2]);
        upd(arc[t],t,1,n,1);
    }
    static priority_queue<int> q;
    for(int t=1;t<=n;++t)
        if(!dr[t]) q.push(t);
    int cnt=0;
    while(q.size()){
        int now=q.top();
        ans[now]=++cnt;
        q.pop();
        for(auto t:e[now])
            if(--dr[t]==0)
                q.push(t);
    }
    for(int t=1;t<=n;++t) printf("%d\n",n-ans[t]+1);
    return 0;
}

原文地址:https://www.cnblogs.com/winlere/p/12241542.html

时间: 2024-10-08 07:00:03

【题解】AT1984 Wide Swap(拓扑排序)的相关文章

20151230训练题解(最短路+拓扑排序)

http://acm.hust.edu.cn/vjudge/contest/view.action?cid=103223#problem/B 这道题用经典的dijsktra算法,大概思路就是用dist[x]存储x到已经确定集合的最短路,n次循环到这个这个最小值,然后更新其他点到新集合的最短路即对应的dist[] 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <al

HDU 5438 拓扑排序+DFS

Ponds Time Limit: 1500/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 3234    Accepted Submission(s): 997 Problem Description Betty owns a lot of ponds, some of them are connected with other ponds by pipes, a

hdu 5438 Ponds 拓扑排序

Ponds Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/contests/contest_showproblem.php?pid=1001&cid=621 Description Betty owns a lot of ponds, some of them are connected with other ponds by pipes, and there will not be more than one

Legal or Not(拓扑排序判环)

http://acm.hdu.edu.cn/showproblem.php?pid=3342 Legal or Not Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 5788    Accepted Submission(s): 2678 Problem Description ACM-DIY is a large QQ group w

UVa 10305 - Ordering Tasks 拓扑排序题解

Topological Sort题解.本题是简单的入门题目. Topological Sort的思想很简单,就是按没有入度的点,先输出,然后删除这个点的出度.然后输出下一组没有入度的点. 如何实现也是很简单的: 这里使用邻接表,建图的时候反过来建图,建立一个入度邻接表. 然后使用一个vis数组,记录访问过的节点,也可以根据这个信息知道哪些是已经输出的点,这个时候这些点的入度可以不算为当前入度了. #include <stdio.h> #include <vector> using

暑假集训之专题----拓扑排序题解

第一单: Problem A Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other) Total Submission(s) : 26   Accepted Submission(s) : 5 Problem Description ACM-DIY is a large QQ group where many excellent acmers get together. It is so h

【基础练习】【拓扑排序】codevs3294 车站分级题解

题目来源:NOIP2013 普及第四题 题目描写叙述 Description 一条单向的铁路线上,依次有编号为1, 2, -, n的n个火车站.每一个火车站都有一个级别,最低为1级.现有若干趟车次在这条线路上行驶.每一趟都满足例如以下要求:假设这趟车次停靠了火车站x.则始发站.终点站之间全部级别大于等于火车站x的都必须停靠. (注意:起始站和终点站自然也算作事先已知须要停靠的网站) 比如,下表是5趟车次的执行情况.当中.前4趟车次均满足要求,而第5趟车次因为停靠了3号火车站(2级)却未停靠途经的

【日常学习】【拓扑排序】家谱树&amp;FZU1483 Sicily1424 奖金 题解

拓扑排序的定义 简单来说就是给你一个图写出一个序列 图中如果a通向b 那么序列中A必须排在B前面 拓扑排序可能有很多结果 必须是有向无环图 可以利用拓扑排序来判定环的存在 当然也可以用神奇的SPFA 但是拓扑排序时间复杂度很低 只有O(V+E) 基本实现思路是 每次取出入度为0的点 然后删除与它相连的边 直到没有边  如果还有边但是找不到入度为0的点 说明有环 学习这个算法联系了两道题目 很经典很单纯 但是一般没有OJ有评测 奖金这道题目在福州大学OJ和中山大学萌萌哒Sicily上找到了评测(为

题解报告:hihoCoder #1174:拓扑排序&#183;一

题目链接:https://hihocoder.com/problemset/problem/1174 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 由于今天上课的老师讲的特别无聊,小Hi和小Ho偷偷地聊了起来. 小Ho:小Hi,你这学期有选什么课么? 小Hi:挺多的,比如XXX1,XXX2还有XXX3.本来想选YYY2的,但是好像没有先选过YYY1,不能选YYY2. 小Ho:先修课程真是个麻烦的东西呢. 小Hi:没错呢.好多课程都有先修课程,每次选课之前都得先查查