[CSP-S模拟测试]:Permutation(线段树+拓扑排序+贪心)
题目描述
你有一个长度为$n$的排列$P$与一个正整数$K$
你可以进行如下操作若干次使得排列的字典序尽量小
对于两个满足$|i−j|\geqslant K$且$|P_i−P_j|=1$的下标$i$与$j$,交换$P_i$与$P_j$
输入格式
第一行包括两个正整数$n$与$K$
第二行包括$n$个正整数,第$i$个正整数表示$P_i$
输出格式
输出一个新排列表示答案
输出共$n$行,第$i$行表示$P_i$
样例
样例输入:
8 3
4 5 7 8 3 1 2 6
样例输出:
1
2
6
7
5
3
4
8
数据范围与提示
对于前$20\%$的数据满足$n\leqslant 6$
对于前$50\%$的数据满足$n\leqslant 2,000$
对于$100\%$的数据满足$n\leqslant 500,000$
题解
这是一道暴力有$90$分的题……
先来考虑如何换,我们每扫到一个位置,发现比它小$1$的在它右边距离大于$K$的位置就交换,不断的扫整个序列,直到无法交换为止,这时候肯定是最优的。
交换不大于$n$次,瓶颈就在于如何快速查询交换的位置。
首先,我们设$pos[i]$表示权值为$i$的数字在哪儿,即先当与权值与下标调换。
那么,我们另$P_i$的字典序最小也就是另$pos[i]$的字典序最小,则操作转化为:相邻元素且权值差$\geqslant K$可以交换。
接着,问题开始抽象化,我们考虑建图……
先来考虑暴力建边,如果$i$与后面的$j$相比,$abs(pos[i]-pos[j])<K$则其顺序已经确定,那么可以相互连边,然后跑拓扑。
但是暴力建边显然无论是时间还是空间都会死掉(还是$90$分……)
那么我们靠有些边是无用的,即如果$A\rightarrow B$且$B\rightarrow C$,那么$A\rightarrow C$这条边就是无用的,但是显然我们现在的策略无法避免,考虑如何处理。
这种情况我们一般都考虑倒着做,因为$pos[i]$连向$(pos[i]-K,pos[i])\cup(pos[i],pos[i]+K)$,但是我们只需要分别连向两个区间内下标最小的那个,用线段树快速查询即可。
时间复杂度:$\Theta(n\log n)$。
期望得分:$100$分。
实际得分:$100$分。
代码时刻
#include<bits/stdc++.h>
#define L(x) x<<1
#define R(x) x<<1|1
using namespace std;
struct rec{int nxt,to;}e[1000001];
int head[500001],cnt;
int n,K;
int tr[2000001];
int pos[500001],du[500001];
int ans[500001];
priority_queue<int,vector<int>,greater<int> > q;
void add(int x,int y)
{
e[++cnt].nxt=head[x];
e[cnt].to=y;
head[x]=cnt;
}
void pushup(int x){tr[x]=min(tr[L(x)],tr[R(x)]);}
void insert(int x,int l,int r,int k,int w)
{
if(l==r){tr[x]=w;return;}
int mid=(l+r)>>1;
if(k<=mid)insert(L(x),l,mid,k,w);
else insert(R(x),mid+1,r,k,w);
pushup(x);
}
int ask(int x,int l,int r,int L,int R)
{
if(r<L||R<l)return 0x3f3f3f3f;
if(L<=l&&r<=R)return tr[x];
int mid=(l+r)>>1;
return min(ask(L(x),l,mid,L,R),ask(R(x),mid+1,r,L,R));
}
int main()
{
scanf("%d%d",&n,&K);
memset(tr,0x3f,sizeof(tr));
for(int i=1;i<=n;i++){int a;scanf("%d",&a);pos[a]=i;}
for(int i=n;i;i--)
{
int x;
x=ask(1,1,n,pos[i]+1,min(pos[i]+K-1,n));
if(x!=0x3f3f3f3f){add(pos[i],pos[x]);du[pos[x]]++;}
x=ask(1,1,n,max(1,pos[i]-K+1),pos[i]-1);
if(x!=0x3f3f3f3f){add(pos[i],pos[x]);du[pos[x]]++;}
insert(1,1,n,pos[i],i);
}
int now=0;
for(int i=1;i<=n;i++)
if(!du[i])q.push(i);
while(!q.empty())
{
int x=q.top();q.pop();
ans[x]=++now;
for(int i=head[x];i;i=e[i].nxt)
if(!(--du[e[i].to]))q.push(e[i].to);
}
for(int i=1;i<=n;i++)printf("%d\n",ans[i]);
return 0;
}
rp++
[CSP-S模拟测试]:Permutation(线段树+拓扑排序+贪心)的更多相关文章
- BZOJ4383 Pustynia(线段树+拓扑排序)
线段树优化建图暴力拓扑排序即可.对于已确定的数,拓扑排序时dp,每个节点都尽量取最大值,如果仍与已确定值矛盾则无解.叶子连出的边表示大于号,其余边表示大于等于. #include<iostrea ...
- hdu 5195 DZY Loves Topological Sorting 线段树+拓扑排序
DZY Loves Topological Sorting Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/sho ...
- HDU5638 / BestCoder Round #74 (div.1) 1003 Toposort 线段树+拓扑排序
Toposort 问题描述 给出nn个点mm条边的有向无环图. 要求删掉恰好kk条边使得字典序最小的拓扑序列尽可能小. 输入描述 输入包含多组数据. 第一行有一个整数TT, 表示测试数据组数. 对 ...
- BZOJ3832[Poi2014]Rally——权值线段树+拓扑排序
题目描述 An annual bicycle rally will soon begin in Byteburg. The bikers of Byteburg are natural long di ...
- 【bzoj3638】Cf172 k-Maximum Subsequence Sum 模拟费用流+线段树区间合并
题目描述 给一列数,要求支持操作: 1.修改某个数的值 2.读入l,r,k,询问在[l,r]内选不相交的不超过k个子段,最大的和是多少. 输入 The first line contains inte ...
- BZOJ.3638.CF172 k-Maximum Subsequence Sum(模拟费用流 线段树)
题目链接 各种zz错误..简直了 /* 19604kb 36292ms 题意:选$k$段不相交的区间,使其权值和最大. 朴素线段树:线段树上每个点维护O(k)个信息,区间合并时O(k^2),总O(mk ...
- BZOJ_3012_[Usaco2012 Dec]First!_trie树+拓扑排序
BZOJ_3012_[Usaco2012 Dec]First!_trie树+拓扑排序 题意: 给定n个总长不超过m的互不相同的字符串,现在你可以任意指定字符之间的大小关系.问有多少个串可能成为字典序最 ...
- BZOJ_4010_[HNOI2015]菜肴制作_拓扑排序+贪心
BZOJ_4010_[HNOI2015]菜肴制作_拓扑排序+贪心 Description 知名美食家小 A被邀请至ATM 大酒店,为其品评菜肴. ATM 酒店为小 A 准备了 N 道菜肴,酒店按照为菜 ...
- 【8.26校内测试】【重构树求直径】【BFS模拟】【线段树维护DP】
题目性质比较显然,相同颜色联通块可以合并成一个点,重新建树后,发现相邻两个点的颜色一定是不一样的. 然后发现,对于一条链来说,每次把一个点反色,实际上使点数少了2个.如下图 而如果一条链上面有分支,也 ...
随机推荐
- 2019_Chrome和ChromeDriver对应关系
Chrome和ChromeDriver对应关系 ChromeDriver下载地址:http://chromedriver.storage.googleapis.com/index.html Chrom ...
- Linux命令整理 - 通用版
通用版 - 系统架构 /dev 设备文件夹 null 有去无回 mouse /sbin 系统管理必备程序 cfdisk.dhcpcd.dump.e2fsck.fdisk.halt.ifconfig.i ...
- linux如何处理多连接请求?
1.TCP迭代服务器程序 这种方式就是服务器同一时间只处理一个客户端的请求,这个请求处理完以后才转向下一个客户请求.当然这样的服务器程序比较少见,这就像一个公司只能一次处理一个客户,后面的客户只能等待 ...
- VC调试方法大全
VC调试方法大全 一.调试基础 调试快捷键 F5: 开始调试 Shift+F5: 停止调试 F10: 调试到下一句,这里是单步跟踪 F11: 调试到下一句,跟进函数内部 Shift+F11: ...
- synchronized的底层实现原理
转自:http://www.cnblogs.com/paddix/p/5367116.html 如果对上面的执行结果还有疑问,也先不用急,我们先来了解Synchronized的原理,再回头上面的问题就 ...
- 使用NMAP端口扫描代码实现
Nmap是一个网络连接端扫描软件,用来扫描网上电脑开放的网络连接端.确定哪些服务运行在哪些连接端,并且推断计算机运行哪个操作系统(这是亦称 fingerprinting).其基本功能有三个,一是探测一 ...
- 创建客户端项目并读取服务化的配置中心(Consul + Spring Cloud Config)
创建客户端项目并读取服务化的配置中心 将配置中心注册到服务中心(Consul) POM文件添加依赖: <dependency> <groupId>org.springframe ...
- 小白学Python(16)——pyecharts 绘制地理图表 Geo
Geo-基本示例 from example.commons import Faker from pyecharts import options as opts from pyecharts.char ...
- C#判断页面中的多个文本框输入值是否有重复的实现方法
List<string> list = new List<string>();//首先定义一个泛型数组 //这里假如说有四个文本框 string mainseat = this ...
- org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [dx.service.ItemService] found for dependency
在整合ssm框架,测试service层的时候报错 Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: ...