zoukankan      html  css  js  c++  java
  • Atcoder 123D Yet Another Sorting Problem

    Problem Statement

    Given is a sequence pp of length N+MN+M, which is a permutation of (1,2…,N+M)(1,2…,N+M). The ii-th term of pp is pipi.

    You can do the following Operation any number of times.

    Operation: Choose an integer nn between 11 and NN (inclusive), and an integer mm between 11 and MM (inclusive). Then, swap pnpn and pN+mpN+m.

    Find the minimum number of Operations needed to sort pp in ascending order. We can prove that it is possible to sort pp in ascending order under the Constraints of this problem.

    Constraints

    • All values in input are integers.
    • 1≤N,M≤1051≤N,M≤105
    • 1≤pi≤N+M1≤pi≤N+M
    • pp is a permutation of (1,2…,N+M)(1,2…,N+M).

    Input

    Input is given from Standard Input in the following format:

    NN MM
    p1p1 ⋯⋯ pN+MpN+M
    

    Output

    Print the minimum number of Operations needed to sort pp in ascending order.


    Sample Input 1 Copy

    Copy

    2 3
    1 4 2 5 3
    

    Sample Output 1 Copy

    Copy

    3
    

    Sample Input 2 Copy

    Copy

    5 7
    9 7 12 6 1 11 2 10 3 8 4 5
    

    Sample Output 2 Copy

    Copy

    10
    

    题目翻译

    给定一个长度为 $N + M $ 的排列。

    你每次可以选择前 (N) 个数中的一个以及后 $M $ 个数中的一个并将它们交换。

    你需要求出,至少需要多少次交换操作才能使得排列变为 (1,2,3,⋯,N + M)

    题目解析

    首先假设位置小于(N)的为左边,([N+1,N+M])为右边

    如果可以交换同一边的数字,那么只要(i)(a_i)连边,每个大小为(S)的连通块都能通过(S-1)次操作完成交换。令连通块数量为(K),操作次数为(N+M-K)

    考虑到只有不同边的数字能交换的限制,按上述方式建图,如果一个联通块同时包括左边和右边的数字,则仍然可以通过(S-1)次还原。

    如果连通块只包含左边或者右边的数字,设只属于左边的连通块数量为(X),只属于右边的连通块数量为(Y)。只要那(X)个连通块和(Y)个连通块任意交换一个数字,就可以满足连通块同时包含左边和右边数字的条件

    最后答案为(N+M-K+2*max(X,Y))

    联通块维护并查集即可

    注意:需要考虑连通块只有1个的情况,即(i)一开始就位于目标位置,不需要与其他联通块交换。不能算在(X)(Y)个单边联通块里面

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    int n,m,set[200005],cntL[200005],cntR[200005],a[200005];
    int find(int x){
        if (set[x]==x) return x;
        return set[x]=find(set[x]);
    }
    int main(){
        scanf("%d%d",&n,&m);
        for (int i=1;i<=n+m;i++){
            scanf("%d",&a[i]);
            set[i]=i;
            if (i<=n) cntL[i]=1;
            else cntR[i]=1;
        }
        for (int i=1;i<=n+m;i++){
            int x=find(i),y=find(a[i]);
            if (x!=y) {
                set[x]=y;
                cntL[y]+=cntL[x];
                cntR[y]+=cntR[x];
            }
        }
        int x=0,y=0,k=0;
        for (int i=1;i<=n+m;i++){
            if (find(i)==i) {
                k++;
                if (cntL[i]+cntR[i]==1) continue;//自己位置不需要交换
                if (cntL[i]==0) x++;
                if (cntR[i]==0) y++;
            }
        }
        cout<<n+m-k+2*max(x,y)<<endl;
    }
    
  • 相关阅读:
    Pycharm中导入Python包的方法
    关于SOA架构设计的案例分析
    浅谈12306核心模型设计思路和架构设计
    美图数据统计分析平台架构演进
    有赞搜索系统的架构演进
    美团云的网络架构演进之路
    数据蜂巢架构演进之路
    1号店电商峰值与流式计算
    京东B2B业务架构演变
    饿了么:业务井喷时订单系统架构的演进
  • 原文地址:https://www.cnblogs.com/Y-E-T-I/p/15135397.html
Copyright © 2011-2022 走看看