首页 > 其他分享 >Codeforces Round #842 (Div. 2)

Codeforces Round #842 (Div. 2)

时间:2023-01-08 13:00:10浏览次数:35  
标签:842 int 元素 交换 Codeforces 数组 Div rightarrow 逆序

D - Lucky Permutation(置换环)

题目大意
给定一个数组,该数组为1到n的全排列。
可以交换数组中两个不同元素的位置(无需相邻)
要使该数组的逆序对恰好为1,最少要多少次交换?

解题思路
逆序对为1的数组只可能是1到n按升序排列后交换相邻两元素得到的数组。
比如2,1,3,4,5...n就是逆序对为1的数组。

我们现在考虑根据原数组建立置换环。

置换环的思想就是:对每个元素,将其指向其排序后应该放到的位置,直到首位相接形成了一个环。
这里我们用元素的下标代表该元素。

比如对于数组[3,4,2,1],若要将其变为1,2,3,4,其对应的环应该为:

一号位上的元素是3,那么它应该放到3号位,所以有\(1\rightarrow 3\),其它的元素按照相同的关系建边即可。

现在考虑交换数组中的元素对这个图有什么影响,交换3,2(即一号位的元素与三号位的元素),数组变为[2,4,3,1],图变为

因为三号位的元素就是3,所以形成自环。
交换3,4(即一号位的元素与二号位的元素),数组变为[4,3,2,1],图变为

事实上,交换两个元素就是交换其对应点的出边。
我们的最终目的,就是将图变成这个样子:

这就表示每个位置的元素都已归位。
要将一个图变成这样就是不断交换一条边的相邻两个节点,每次交换都能分离出一个节点形成自环,最少交换次数就是节点数减1。(为什么这样交换次数最少,证明起来好像还有点麻烦)

搞清楚交换元素与图的关系,问题就变得简单了。
刚刚是把数组变为1,2,3,4,现在变为逆序对位1的数组,比如变成2,1,3,4,对应的图应该是:

原来的元素1(其对应的位置是四号位)要回到一号位,现在要去二号位,元素2(三号位)原来要回到二号位,现在要去一号位。用\(x,\ y\)表示我们最后需要的逆序对,\(p_x,\ p_y\)表示他们在原数组中的位置,上图发生的变化就是在原图中断开\(p_x\rightarrow x\)与\(p_y\rightarrow y\),
重连\(p_x\rightarrow y\)与\(p_y\rightarrow x\)。
容易发现若\(x,\ y\)在同一个环中,这种操作会使环的数目加1,
若不在同一个环中,会使环的数目减1。
而我们要使所有节点变为自环的操作数使节点数目-环的数目。
所以我们只需要先把原图求出来,再一次判断相邻元素是否在同一个环中即可。

参考代码

#include <bits/stdc++.h>
using namespace std;
const int  N = 2e5 + 10;
int a[N];
void work()
{
    int n;
    cin >> n;
    for (int i = 1; i <= n; ++i)
    {
        cin >> a[i];
    }
    int ans = n, ind = 1;
    vector<int> p(n + 1, 0);
    for (int i = 1; i <= n; ++i)
    {
        int t = a[i];
        if (p[t])
            continue;
        while (p[t] == 0)
        {
            p[t] = ind;
            t = a[t];
        }
        ++ind, --ans;
    }
    for (int i = 1; i < n; ++i)
    {
        if (p[i] == p[i + 1])
        {
            cout << ans - 1 << endl;
            return ;
        }
    }
    cout << ans + 1 << endl;
    return ;
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    int T;
    cin >> T;
    while (T--)
    {
        work();
    }
    return 0;
}

标签:842,int,元素,交换,Codeforces,数组,Div,rightarrow,逆序
From: https://www.cnblogs.com/hetailang/p/17033402.html

相关文章

  • Educational Codeforces Round 14
    EducationalCodeforcesRound14https://codeforces.com/contest/6914/6:ABCD(C是恶心人的模拟分类讨论,写了巨久导致没时间看EF)这场没有红题,应该是可以补完的。A.Fas......
  • Codeforces Round #839 (Div. 3) A-E
    CodeforcesRound#839(Div.3)A-Ehttps://codeforces.com/contest/1772之前打的一场忘记记录了,题也没补,今天想起来E博弈没过补一下,FG不想看了好长qwq做太久已经忘了......
  • CodeForces - 1760F Quests
    CodeForces-1760FQuests题解:二分答案首先我们来分析一题目,如果说K越大,我们在d天里很有可能得不到C个硬币,所以K的最大值一定在合法答案和不合法答案的临界点,并且这些......
  • Codeforces - 1656E - Equal Tree Sums(构造 + 树论 + 图论 + 搜索、结论题、*2200)
    1656E-EqualTreeSums(⇔源地址)目录1656E-EqualTreeSums(⇔源地址)tag题意思路AC代码错误次数:0tag⇔*2200、⇔构造、⇔树论、⇔图论、⇔搜......
  • CF#842-div2-C
    题意给定一个序列A,让你构造两个序列BC满足:\(max(B[i],C[i])=A[i]\)能构造输出YES然后输出两个构造序列BC,不能构造输出NO题解显然,我想到如果A序列中出现三个及以......
  • bug|记录某次页面div使用v-html标签渲染图片等内容的过程
    前言记录某次页面div使用v-html标签渲染图片等内容的过程一、结论:get请求但被设置Sec-Fetch-*请求头的图片无法展示。二、原因:1.本项目中的img标签发起get请求,目标链......
  • 1.4 SMU Winter 2023 Round #1 (Div.2)
    [语言月赛202212]不可以,总司令思路:比较大小 if(x>y)cout<<"NO";elseif(x<y)cout<<"YES";elsecout<<"equalprobability"; [语言月赛202212]计算......
  • 1.7 vp Codeforces Round #839 (Div. 3)
    A-A+B?题意:给出两个0~9的数字和一个加号。要求输出数字相加的和思路:用字符串输入,第一位和第三位相加减去两个字符0即为数字和。voidsolve(){ strings; cin>>s;......
  • 使用div+css实现表格布局
    DIV+CSS是WEB设计标准,它是一种网页的布局方法。与传统中通过表格(table)布局定位的方式不同,它可以实现网页页面内容与表现相分离。提起​​DIV+CSS​​​组合,还要从XHTML说起......
  • [ABC254Ex] Multiply or Divide by 2 题解
    [ABC254Ex]MultiplyorDivideby2Solution目录[ABC254Ex]MultiplyorDivideby2Solution更好的阅读体验戳此进入题面SolutionCodeUPD更好的阅读体验戳此进入题......