首页 > 其他分享 >ARC167D Good Permutation 题解

ARC167D Good Permutation 题解

时间:2023-10-15 23:55:26浏览次数:45  
标签:Good int 题解 rep mn maxN getfa ARC167D define

题意

给定一个长度为 \(N\) 的排列 \((P_1,P_2,\cdots,P_N)\)。称一个排列 \(P\) 为“好排列”当且仅当对于所有 \(1\leq x\leq N\),都能通过不停地使 \(x\leftarrow P_x\) 将 \(x\) 变成 \(1\)。

通过最小次数操作将 \(P\) 变成“好排列”,每次操作为交换 \(P\) 中的两个数 \(P_i\) 和 \(P_j\)。并且在保证操作次数最小的情况下使最后的 \(P\) 字典序最小,求最后的 \(P\)。

题解

这种不停地跳的问题显然想到 \(i\rightarrow P_i\) 连边,则原序列的图为一个个环。显然,最小操作次数为 环的数量 - 1,因为每次操作只要选不同环上的两个点,交换它们连向的点就可以把两个环合并为一个环。

考虑如何操作使字典序最小,我们从小到大依次考虑每个位置能放的最小的数。显然,一个位置上的数除了自己环上的其他都可以放。

则可以用一个 set 维护所有环上的最小值,每次寻找不是自己环上的最小值(只可能是 begin 或这 begin 的下一个),如果比当前值小,直接交换即可,这个最小值可以用并查集维护。

考虑到一个问题,就比如 2 1 4 3 这个样例,在第一个环 2 1 上显然不会交换,但在第二个环 4 3 上就会和 1 交换,这样显然是不优的。解决的方法就是我们强制钦定每个环在最后一个必须交换,这样在 1 的时候就会和 3 交换,把两个环合并为一个,避免了不优的问题。

时间复杂度 \(\mathcal{O}(n\log n)\)。

代码

#include <bits/stdc++.h>
#define rep(i, j, k) for(int i = (j); i <= (k); i++)
#define per(i, j, k) for(int i = (j); i >= (k); i--)
#define ll long long
#define vi vector<int>
#define sz(a) ((int)(a.size()))
#define mset(f, x) memset(f, x, sizeof(f))
#define ALL(x) (x).begin(), (x).end()
#define rALL(x) (x).rbegin(), (x).rend()
#define uni(x) x.resize(unique(ALL(x)) - x.begin())
#define ull unsigned long long
using namespace std;
const int maxN = 2e5 + 10;
int n, p[maxN], pre[maxN];
int fa[maxN], mx[maxN], mn[maxN];
set<int> S;
int getfa(int x) {if(fa[x] == x) return x; return fa[x] = getfa(fa[x]);}
void merge(int x, int y) {
    x = getfa(x), y = getfa(y);
    if(x == y) return;
    fa[x] = y;
    mx[y] = max(mx[y], mx[x]);
    mn[y] = min(mn[y], mn[x]);
}
void Main() {
    cin >> n;
    rep(i, 1, n) {
        cin >> p[i];
        fa[i] = i;
        mx[i] = mn[i] = i;
    }
    rep(i, 1, n) {
        pre[p[i]] = i;
        merge(i, p[i]);
    }
    rep(i, 1, n) if(getfa(i) == i) S.insert(mn[i]);
    rep(i, 1, n - 1) {
        if((int)S.size() == 1) break;
        auto it = S.begin();
        if((*it) == mn[getfa(i)]) it++;
        int val = (*it);
        if(val < p[i] || i == mx[getfa(i)]) {
            S.erase(mn[getfa(i)]);
            S.erase(mn[getfa(val)]);
            merge(i, val);
            S.insert(mn[getfa(i)]);
            int tmp = pre[val];
            swap(pre[p[i]], pre[val]);
            swap(p[i], p[tmp]);
        }
    }
    rep(i, 1, n) cout << p[i] << " "; cout << "\n";
}
int main() {
	ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
	int t; cin >> t; while(t--) Main();
	return 0;
}

标签:Good,int,题解,rep,mn,maxN,getfa,ARC167D,define
From: https://www.cnblogs.com/Jerry-Jiang/p/17766461.html

相关文章

  • [CSP-S2019] 树的重心 题解
    [CSP-S2019]树的重心因为这道题令我十分兴奋,所以来写一下做完后的思考。这道题用到了树的重心的种种性质,在写解法的时候会一一点出其用处。首先,枚举每一条边,然后各自\(O(n)\)扫一次的\(O(n^2)\)做法是简单的。那么接下来,就会出现不同的解法了:优化\(O(n)\)求解的过程......
  • P9290 Luna likes Love 题解
    原题:[洛谷P9310]([P9310EGOI2021]LunalikesLove/卢娜爱磕cp-洛谷|计算机科学教育新生态(luogu.com.cn))题目大意给定一个长度为\(\large2n(n\leq10^5)\)的序列,序列中\(\large1\simn\)的每一个数都恰好出现两次。可进行两种操作:交换两个相邻的数的位置。......
  • 2023 香山杯 RE部分题解
      URL从哪里来 main函数断点下载这里 然后可以看到TempFileName,是out.exe.tmp,还包含路径,直接提取出来用IDA打开,一开始被url误导了,看到了下面的RC4加密去了,使用findcryt软件,看到一个base64加密,交叉引用 在这动态调试这个函数 里面的a1,有一串字符是base64密文 ,解......
  • 【ZROJ2730】简单题 可持久化分块题解
    Description给定一棵\(n\)个节点的树,每次询问编号为\([l,r]\)的点中有多少个是祖先关系。\(n,q\le10^5\)。Solution直接做的话树上的祖先关系不好统计,那么转化到\(\texttt{dfs}\)序上,如果\(u\)是\(v\)的祖先那么\(dfn_u\ledfn_v<dfn_u+siz_u\)。把\([d......
  • AtCoder Beginner Contest 324 DF题题解
    比赛链接D-SquarePermutation其实比较简单,但是比赛时候脑子不转了,竟然在尝试枚举全排列,然后算了一下复杂度直接不会做了。正解应该是枚举完全平方数,底数枚举到\(sqrt(10^{14})\)即可,因为n最大为13。然后统计一下这个完全平方数各个数字出现了多少个,和读入的比较一下是......
  • 网络规划设计师真题解析--HDLC(帧类型)
    HDLC协议通信过程如下图所示,其中属于U帧的是(13)。(2021)A.仅SABME          B.SABME和UA C.SABME、UA和REJ,1    D.SABME、UA和I,0,0答案:B解析:HDLC帧类型如图:bit01234567I帧0N(S)发送帧序号3bit,取值23(0-7)P/FN(R)下一个预期要接收帧的序号3bit,取值23(0-7)S帧10S......
  • ABC324题解
    A/B赛时没打。C暴力判断是相等s[i]==t还是替换了一个字符,或者是添加/删除了一个字符。最后两个判断只需要交换一下\(s\)和\(t\)的顺序就可以共用一个函数了。D注意到\(N\le13\),所以平方数不会超过\(v=10^{13}\),很容易想到暴力枚举\(\sqrtv\)以内的数,判断是否......
  • P9517 drink 题解
    P9517drink题解Part1提示题目传送门欢迎大家指出错误并私信这个蒟蒻欢迎大家在下方评论区写出自己的疑问(记得@这个蒟蒻)Part2更新日志2023-08-1218:06文章完成2023-08-1415:53文章通过审核Part3解析这道题考场上用的查找做的。先用一个结构体分别表示......
  • P9686 Judg. 题解
    P9686Judg.题解Part1提示题目传送门欢迎大家指出错误并私信这个蒟蒻欢迎大家在下方评论区写出自己的疑问(记得@这个蒟蒻)Part2更新日志2023-10-0215:50文章完成2023-10-0412:37文章通过审核Part3解析一道简单模拟。这道题最简单的方法就是直接在for循......
  • P8741 [蓝桥杯 2021 省 B] 填空问题 题解
    P8741[蓝桥杯2021省B]填空问题题解题目传送门欢迎大家指出错误并联系这个蒟蒻更新日志2023-05-0923:19文章完成2023-05-0923:20通过审核2023-06-2021:03优化了文章代码格式试题A:空间【解析】本题考察计算机存储的基础知识,只要掌握空间存储的换算方法,就能......