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

[ARC167D] Good Permutation 题解

时间:2023-10-16 17:25:33浏览次数:25  
标签:std Good 题解 valueType 元素 交换 集合 ARC167D

题意

对于一个长度为 \(N\) 的排列 \(Q\),定义其为好的,当且仅当

  • 对于任意整数 \(i \in \left[1, N\right]\),在进行若干次操作 \(i \leftarrow Q_i\) 后可以得到 \(i = 1\)。

给定一个排列 \(P\),定义一次操作为交换两个数。定义 \(M\) 为可以将 \(P\) 变为一个好的的排列的最小操作次数,求在操作 \(M\) 次的情况下可以得到的字典序最小的排列。

(\(1 \le N \le 2 \times 10^5\))。

题解

转化为图论模型,考虑对于对于所有 \(i \in \left[1, N\right]\),建边 \(i \rightarrow P_i\),因为每个点的出度和入度均为 \(1\),所以建出的图一定是若干个环。而一个好的排列最后建出的图就是一个长度为 \(N\) 的环。而每次操作实质上就是合并两个环。

由于所有节点最后均与 \(1\) 在统一个环中,并且我们要求字典序最小,那么我们可以从小到大去枚举一个元素 \(i\),若其与 \(1\) 不在同一个环中就交换其所在环的一个元素与 \(1\) 所在环的一个元素,考虑到需要字典序最小,那么我们可以交换与 \(1\) 在同一个环的所有元素中第一个大于当前元素,若与 \(1\) 在同一个环的所有元素均小于当前元素,那么我们将其与最后一个位置交换。

若出现后者的情况,可以发现与 \(1\) 联通的集合为 \(\left\{1, 2, 3, \cdots, i - 1\right\}\),由于值的集合和下标集合相同,所以这种情况下 \(i\) 会与 \(P_{i - 1}\) 交换。若出现前者的情况,由于其是一个环,那么一定存在边 \(u \rightarrow v\) 满足, \(u < i - 1, v > i\),即存在 \(j \le i - 1, P_j > i\)。此时的 \(j\) 一定满足对于任意 \(k < j\),有 \(P_k < i \Rightarrow P_k < i + 1\),也就是说被 \(i\) 排除的位置集合也不可能进入 \(i + 1\) 的决策集合,换句话说,每次交换位置的位置是单调递增的。那么我们使用一个指针 \(j\) 去维护即可,若找到了 \(P_j > i\) 或扫描到了 \(i - 1\) 那么就执行交换操作。

总复杂度 \(\mathcal{O}(N)\),可以通过本题。

Code

#include <bits/stdc++.h>

typedef int valueType;
typedef std::vector<valueType> ValueVector;
typedef std::vector<bool> bitset;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);

    valueType T;

    std::cin >> T;

    for (int testcase = 0; testcase < T; ++testcase) {
        valueType N;

        std::cin >> N;

        ValueVector P(N + 1), pos(N + 1);

        for (valueType i = 1; i <= N; ++i) {
            std::cin >> P[i];

            pos[P[i]] = i;
        }

        valueType pointer = 1;

        bitset visited(N + 1, false);

        {
            valueType y = pos[1];

            while (!visited[P[y]]) {
                visited[P[y]] = true;

                y = P[y];
            }
        }

        for (valueType i = 1; i <= N; ++i) {
            if (visited[i])
                continue;

            valueType const x = pos[i];

            while (pointer < i - 1)
                if (P[pointer] < i)
                    ++pointer;
                else
                    break;

            {
                valueType y = x;

                while (!visited[P[y]]) {
                    visited[P[y]] = true;

                    y = P[y];
                }
            }
            std::swap(P[x], P[pointer]);
        }

        std::copy(P.begin() + 1, P.end(), std::ostream_iterator<valueType>(std::cout, " "));

        std::cout << std::endl;
    }

    std::cout << std::flush;

    return 0;
}

标签:std,Good,题解,valueType,元素,交换,集合,ARC167D
From: https://www.cnblogs.com/User-Unauthorized/p/solution-ARC167D.html

相关文章

  • 计算机网络的分组转发算法例题解析
    例题展示例题解决将题目中要求的ip地址与相对应的子网掩码进行二进制上面的相与即可,若是与目的ip地址一致,那么就直接跳转到其对应的那个接口;否则就直接跳转到默认接口;本题答案为R2;......
  • UVA1366 Martian Mining 题解
    这个题可以用动态规划解决。令\(sbe_{i,j}\)为第\(j\)列\(1\)至\(i\)个格子\(BE\)矿总和,令\(snw_{i,j}\)为第\(i\)行\(1\)至\(j\)个格子\(NEW\)矿总和。\(dp_{i,j,0}\)表示为以第(\(i\),\(j\))为右下角,第(\(i\),\(j\))号格子建立\(BE\)矿管道的最大采矿量。\(dp......
  • P8854 [POI2002] 超级马 题解
    这题其实就是搜索,不知道怎么评绿的。题意有一个大小无限的棋盘,有一只马,给定\(n\)种跳法,判断马是否能跳到棋盘所有点。题解搜索马是否可以跳到他上下左右的四个点,因为只要能跳到这四个点,就可以以这四个点为基础跳到其他所有的点。这里有一些细节需要处理:因为每次操作能是......
  • CF1873E Building an Aquarium 题解
    这题看到第一眼就是二分。单调性二分最关键的东西是单调性在哪。单调性是如果高度越高,需要的水就越多,高度越矮,要用的水越少。不难得出代码:check函数:intcheck(intmid){ intsum=0; for(inti=1;i<=n;i++){ sum+=max(0ll,mid-a[i]); } if(sum<=x)returnsum; elsere......
  • html2canvas 截图不全问题解决
    有个低代码平台项目,需求是要将canvas画布上的echarts图表等组件截图保存,如果是正常比例(也就是百分百比例)截图是正常的,但如果画布处于缩放状态进行截图的话就会因组件上的一些样式影响而导致截图不全。为了解决这一问题,在网上也查找了很多资料,终于找到解决办法,亲测有效。话不多说,......
  • 第二届“梦羽杯”题解
    前言特别鸣谢出(蒯)题人:CJYA原题:NOIP2008普及组T4《立体图》B原题:HAOI2007反素数C......
  • 题解 AcWing 1272. 与众不同
    题目描述定义完美序列:若一个序列内没有重复的数,称这个数列为完美数列。每次给定一个区间\([l,r]\),求这个区间内最长的完美序列长度。具体思路设\(len_i\)表示从\(i\)出发往右的最长完美序列长度。我们定义一个指针\(st\),表示当前枚举的区间左端点,同时定义多一个指针\(......
  • ARC167D Good Permutation 题解
    题意给定一个长度为\(N\)的排列\((P_1,P_2,\cdots,P_N)\)。称一个排列\(P\)为“好排列”当且仅当对于所有\(1\leqx\leqN\),都能通过不停地使\(x\leftarrowP_x\)将\(x\)变成\(1\)。通过最小次数操作将\(P\)变成“好排列”,每次操作为交换\(P\)中的两个数\(P_i\)......
  • [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\)的每一个数都恰好出现两次。可进行两种操作:交换两个相邻的数的位置。......