【刷题】LOJ 2818 「eJOI2018」循环排序
题目描述
本题译自 eJOI2018 Problem F「Cycle Sort」
给定一个长为 \(n\) 的数列 \(\{a_i\}\) ,你可以多次进行如下操作:
选定 \(k\) 个不同的下标 \(i_1, i_2, \cdots, i_k\)(其中 \(1 \le i_j \le n\) ),然后将 \(a_{i_1}\) 移动到下标 \(i_2\) 处,将 \(a_{i_2}\) 移动到下标 \(i_3\) 处,……,将 \(a_{i_{k-1}}\) 移动到下标 \(i_{k}\) 处,将 \(a_{i_k}\) 移动到下标 \(i_1\) 处。
换言之,你可以按照如下的顺序轮换元素:\(i_1 \rightarrow i_2 \rightarrow i_3 \rightarrow \cdots \rightarrow i_{k-1} \rightarrow i_k \rightarrow i_1\) 。
例如:\(n=4, \{a_i\}=\{ 10, 20, 30, 40\}, i_1=2, i_2=3, i_3=4\) ,则操作完成后的 \(a\) 数列变为 \(\{ 10, 40, 20, 30\}\) 。
你的任务是用操作次数最少的方法将整个数列排序成不降的。注意,所有操作中选定下标的个数总和不得超过 \(s\) 。如果不存在这样的方法(无解),输出 -1。
输入格式
第一行, \(2\) 个整数, \(n\) 和 \(s\ (1 \le n \le 2 \times 10^5, 0 \le s \le 2 \times 10^5)\) 。
第二行, \(n\) 个整数 \(a_1, a_2, a_3, \cdots a_n\) ,表示数列 \(\{a_i\}\) ,其中 \(1 \le a_i \le 10^9\) 。
输出格式
如果无解,仅输出 -1 。
否则,第一行输出一个整数 \(q\) (可以为 \(0\) ,参见样例 3 ),表示最少需要进行的操作次数。
接下来 \(2 \times q\) 行描述每次操作。
对于每次操作,先输出一个整数 \(k\) 表示此操作选定的下标数量,然后在下一行中输出 \(k\) 个整数 \(i_1, i_2, \cdots, i_k\) 。
在操作次数 \(q\) 最少的情况下,你可以输出任意一种可行方案。
样例
样例输入 1
5 5
3 2 3 1 1
样例输出 1
1
5
1 4 2 3 5
样例解释 1
你可以用两次操作 \(1 \rightarrow 4 \rightarrow 1\) 和 \(2 \rightarrow 3 \rightarrow 5 \rightarrow 2\) 排序数组,但这样会 WA,因为你的任务是最小化 \(q\) ,而最优解的 \(q=1\) 。
一种可行的方法是 \(1 \rightarrow 4 \rightarrow 2 \rightarrow 3 \rightarrow 5 \rightarrow 1\) ,即样例输出。
样例输入 2
4 3
2 1 4 3
样例输出 2
-1
样例解释 2
所有操作中选定下标的个数总和的最小值为 \(4\) (一种可行的方法是 \(1 \rightarrow 2 \rightarrow 1\) 和 \(3 \rightarrow 4 \rightarrow 3)\),因此无解。
样例输入 3
2 0
2 2
样例输出 3
0
样例解释 3
数组已经有序,因此不需要进行操作。
样例输入 4
6 9
6 5 4 3 2 1
样例输出 4
2
6
1 6 2 5 3 4
3
3 2 1
样例输入 5
6 8
6 5 4 3 2 1
样例输出 5
3
2
3 4
4
1 6 2 5
2
2 1
补充说明
样例 4 和 5 满足子任务 6 和 7 的限制。
数据范围与提示
子任务编号 | 分数 | 限制 |
---|---|---|
1 | $0$ | 样例 |
$2$ | $5$ | $n, s \le 2$ 且 $1 \le a_i \le 2$ |
$3$ | $5$ | $n \le 5$ |
$4$ | $5$ | $1 \le a_i \le 2$ |
$5$ | $1$$0$ | $\{a_i\}$ 中 $1$ 到 $n$ 的所有正整数出现且恰好只出现一次, $s=2 \times n$ |
$6$ | $10$ | $\{a_i\}$ 中 $1$ 到 $n$ 的所有正整数出现且恰好只出现一次, $n \le 1000$ |
$7$ | $15$ | $\{a_i\}$ 中 $1$ 到 $n$ 的所有正整数出现且恰好只出现一次 |
$8$ | $15$ | $s=2 \times n$ |
$9$ | $15$ | $n \le 1000$ |
$10$ | $20$ | 无特殊限制 |
题解
首先假设没有相同的 \(a_i\)
离散化一下,对于每个点,如果它错位,那么都把它向它本应该在的地方连边。我们就可以得到很多个环,如果没有要求要操作数最小,那么一种方案就是每个环移动一回,直至最后完成
如果错位个数大于允许操作次数,那么肯定是无解的了
特判掉只有一个环的情况
然后有一种和并环的方法,就是把上面得到的所有的环首尾相接连在一起,最后会发现只有每个环的最后一个位置错位,我们再把这些错位的连成一个新的环操作,所以最少次数就是 \(2\) 次
但是这样的移动次数是 错位个数 \(+\) 环数 的,很有可能会超过允许的操作次数,这个时候,我们可以选择不把所有的环合并成一个大环,我们可以把某一些环合并成大环,按照大环的做法去做,而剩下的小环就一个一个自己换,这样可以减少移动次数
所以最后就这样贪心选就好了
如果有相同的 \(a_i\) 也是一样的,同样的离散化,但找环是在一个欧拉图上找的,直接找欧拉回路
#include<bits/stdc++.h>
#define ui unsigned int
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
const int MAXN=200000+10;
int n,s,k,e,a[MAXN],b[MAXN],beg[MAXN],nex[MAXN],to[MAXN],val[MAXN],ext[MAXN],vis[MAXN],use[MAXN],cnt;
std::vector<int> V,ans[MAXN];
std::map<int,int> M;
template<typename T> inline void read(T &x)
{
T data=0,w=1;
char ch=0;
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')w=-1,ch=getchar();
while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
x=data*w;
}
template<typename T> inline void write(T x,char ch='\0')
{
if(x<0)putchar('-'),x=-x;
if(x>9)write(x/10);
putchar(x%10+'0');
if(ch!='\0')putchar(ch);
}
template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
template<typename T> inline T min(T x,T y){return x<y?x:y;}
template<typename T> inline T max(T x,T y){return x>y?x:y;}
inline void discretization()
{
for(register int i=1;i<=n;++i)V.push_back(a[i]);
std::sort(V.begin(),V.end());
V.erase(std::unique(V.begin(),V.end()),V.end());
for(register int i=0,lt=V.size();i<lt;++i)M[V[i]]=i+1;
}
inline void insert(int x,int y,int z)
{
to[++e]=y;
nex[e]=beg[x];
beg[x]=e;
val[e]=z;
}
inline void dfs(int x)
{
vis[x]=cnt;
for(register int &i=beg[x];i;i=nex[i])
if(!use[i])
{
int tmp=i;
use[i]=1;
dfs(to[i]);
ans[cnt].push_back(val[tmp]);
}
}
int main()
{
read(n);read(s);
for(register int i=1;i<=n;++i)read(a[i]);
discretization();
for(register int i=1;i<=n;++i)a[i]=b[i]=M[a[i]];
std::sort(b+1,b+n+1);
for(register int i=1;i<=n;++i)
if(a[i]!=b[i])++k,insert(a[i],b[i],i);
if(k>s)
{
puts("-1");
return 0;
}
for(register int i=1;i<=n;++i)
if(!vis[i]&&beg[i])++cnt,dfs(i);
if(cnt<=1||s-k<=1)
{
printf("%d\n",cnt);
for(register int i=1;i<=cnt;++i)
{
printf("%d\n",ans[i].size());
for(register int j=0,lt=ans[i].size();j<lt;++j)printf("%d ",ans[i][j]);
puts("");
}
return 0;
}
printf("%d\n",cnt-min(s-k,cnt)+2);
for(register int i=s-k+1;i<=cnt;++i)
{
printf("%d\n",ans[i].size());
for(register int j=0,lt=ans[i].size();j<lt;++j)printf("%d ",ans[i][j]);
puts("");
}
if(s-k)
{
int p1=0,p2=0;
for(register int i=min(s-k,cnt);i>=1;--i)p1+=ans[i].size(),ext[++p2]=ans[i][0];
printf("%d\n",p1);
for(register int i=1;i<=min(s-k,cnt);++i)
for(register int j=0,lt=ans[i].size();j<lt;++j)printf("%d ",ans[i][j]);
puts("");
printf("%d\n",p2);
for(register int i=1;i<=p2;++i)printf("%d ",ext[i]);
}
return 0;
}
【刷题】LOJ 2818 「eJOI2018」循环排序的更多相关文章
- *LOJ#2085. 「NOI2016」循环之美
$n \leq 1e9,m \leq 1e9,k \leq 2000$,求$k$进制下$\frac{x}{y}$有多少种不同的纯循环数取值,$1 \leq x \leq n,1 \leq y \leq ...
- LOJ #6436. 「PKUSC2018」神仙的游戏(字符串+NTT)
题面 LOJ #6436. 「PKUSC2018」神仙的游戏 题解 参考 yyb 的口中的长郡最强选手 租酥雨大佬的博客 ... 一开始以为 通配符匹配 就是类似于 BZOJ 4259: 残缺的字符串 ...
- Loj #2553. 「CTSC2018」暴力写挂
Loj #2553. 「CTSC2018」暴力写挂 题目描述 temporaryDO 是一个很菜的 OIer .在 4 月,他在省队选拔赛的考场上见到了<林克卡特树>一题,其中 \(k = ...
- Loj #3096. 「SNOI2019」数论
Loj #3096. 「SNOI2019」数论 题目描述 给出正整数 \(P, Q, T\),大小为 \(n\) 的整数集 \(A\) 和大小为 \(m\) 的整数集 \(B\),请你求出: \[ \ ...
- Loj 3058. 「HNOI2019」白兔之舞
Loj 3058. 「HNOI2019」白兔之舞 题目描述 有一张顶点数为 \((L+1)\times n\) 的有向图.这张图的每个顶点由一个二元组 \((u,v)\) 表示 \((0\le u\l ...
- LOJ #6435. 「PKUSC2018」星际穿越(倍增)
题面 LOJ#6435. 「PKUSC2018」星际穿越 题解 参考了 这位大佬的博客 这道题好恶心啊qwq~~ 首先一定要认真阅读题目 !! 注意 \(l_i<r_i<x_i\) 这个条 ...
- LOJ #6432. 「PKUSC2018」真实排名(组合数)
题面 LOJ #6432. 「PKUSC2018」真实排名 注意排名的定义 , 分数不小于他的选手数量 !!! 题解 有点坑的细节题 ... 思路很简单 , 把每个数分两种情况讨论一下了 . 假设它为 ...
- loj#2012. 「SCOI2016」背单词
题目链接 loj#2012. 「SCOI2016」背单词 题解 题面描述有点不清楚. 考虑贪心 type1的花费一定不会是优的,不考虑, 所以先把后缀填进去,对于反串建trie树, 先填父亲再填儿子, ...
- loj#2718. 「NOI2018」归程
题目链接 loj#2718. 「NOI2018」归程 题解 按照高度做克鲁斯卡尔重构树 那么对于询问倍增找到当前点能到达的高度最小可行点,该点的子树就是能到达的联通快,维护子树中到1节点的最短距离 s ...
随机推荐
- Exp1 PC平台逆向破解(5)M
Exp1 PC平台逆向破解(5)M [ 直接修改程序机器指令,改变程序执行流程] 用命令cp pwn1 20155320备份pwn1 输入objdump -d 20155320反汇编,找到call指令 ...
- GAN初步——本质上就是在做优化,对于生成器传给辨别器的生成图片,生成器希望辨别器打上标签 1,体现在loss上!
from:https://www.sohu.com/a/159976204_717210 GAN 从 2014 年诞生以来发展的是相当火热,比较著名的 GAN 的应用有 Pix2Pix.CycleGA ...
- Hadoop日记Day9---HDFS的java访问接口
一.搭建Hadoop 开发环境 我们在工作中写完的各种代码是在服务器中运行的,HDFS 的操作代码也不例外.在开发阶段,我们使用windows 下的eclipse 作为开发环境,访问运行在虚拟机中的H ...
- Ubuntu 守护进程
项目中用的Qt开发的GUI程序,需要随机自启动. 最初尝试过使用SuperVisor,但是会出现下面的错误. qt.qpa.screen: QXcbConnection: Could not conn ...
- app.use( )做一个静态资源服务
var express = require("express"); var app = express(); //静态服务 app.use("/jingtai" ...
- Join 和 Apply 用法全解
在关系型数据库系统中,为了满足第三范式(3NF),需要将满足“传递依赖”的表分离成单独的表,通过Join 子句将相关表进行连接,Join子句共有三种类型:外连接,内连接,交叉连接:外连接分为:left ...
- Spring+SpringMVC+MyBatis+easyUI整合优化篇(一)Java语言中System.out.print与Log的比较
作者:13 GitHub:https://github.com/ZHENFENG13 版权声明:本文为原创文章,未经允许不得转载. 前言 距离上一次更新博客有一段时间了,主要是因为最近有开发任务,另外 ...
- 2017qq红包雨最强攻略
这个只支持苹果手机,而且要有苹果电脑,只有苹果手机是不行的. QQ红包规则:只要你到达指定的位置,就可以领取附近的红包,一般也就几毛,还有几分的,当然也不排除有更高的,只不过我是没遇到... 那么既然 ...
- 【DDD】领域驱动设计实践 —— 业务建模战术
本文结合团队在COMMUNITY(社区服务系统)业务建模过程中的实践经验,总结得到一些DDD业务建模的小招数,不一定是完美的,但是对我们团队来说很有效用,希望能帮到其他人.后面会陆续将项目中业务建模的 ...
- 异步编程之asyncio简单介绍
引言: python由于GIL(全局锁)的存在,不能发挥多核的优势,其性能一直饱受诟病.然而在IO密集型的网络编程里,异步处理比同步处理能提升成百上千倍的效率,弥补了python性能方面的短板. as ...