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

Codeforces Round #842 (Div. 2) A-D

时间:2023-01-06 17:57:17浏览次数:60  
标签:qu 842 int 复杂度 元素 pos long Codeforces Div

比赛链接

A

题意

给一个数 \(k\) 找到最大的 \(x\) ,满足 \(1 \leq x < k\) 且 \(x!+(x-1)!\) 是 \(k\) 的倍数。

题解

知识点:数学。

猜测 \(x = k-1\) ,证明 \((k-1)! + (k-2)! = (k-1+1) \cdot(k-2)! = k \cdot (k-2)!,k \geq 2\) 。

因此 \(x = k-1\) 。

时间复杂度 \(O(1)\)

空间复杂度 \(O(1)\)

代码

#include <bits/stdc++.h>
#define ll long long

using namespace std;

bool solve() {
    int k;
    cin >> k;
    cout << k - 1 << '\n';
    return true;
}

int main() {
    std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int t = 1;
    cin >> t;
    while (t--) {
        if (!solve()) cout << -1 << '\n';
    }
    return 0;
}

B

题意

给一个长为 \(n\) 的排列,每次操作从排列中取出 \(k\) 个数,从小到大排序好放回排列尾部。问最少操作多少次,才能将原排列变成从小到大排序好的排列。

题解

知识点:贪心。

注意到每次操作都会把数字放到尾部,不会影响之前数字的相对位置。因此为了使得操作最小化,我们先找到不用选的数字有多少,显然我们需要从 \(1\) 开始递增往后找。设 \(pos\) 是第一个要选的数字,那么答案便是 \(\Big\lceil \dfrac{n - pos + 1}{k} \Big\rceil\) 。

时间复杂度 \(O(n)\)

空间复杂度 \(O(n)\)

代码

#include <bits/stdc++.h>
#define ll long long

using namespace std;

int a[100007];
bool solve() {
    int n, k;
    cin >> n >> k;
    for (int i = 1;i <= n;i++) cin >> a[i];
    int pos = 1;
    for (int i = 1;i <= n;i++) {
        if (pos == a[i]) pos++;
    }
    cout << (n - pos + 1 + k - 1) / k << '\n';
    return true;
}

int main() {
    std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int t = 1;
    cin >> t;
    while (t--) {
        if (!solve()) cout << -1 << '\n';
    }
    return 0;
}

C

题意

给出 \(n\) 个数 \(a_i\) ,要求两个长为 \(n\) 的排列 \(p,q\) 使得 \(a_i = \max(p_i,q_i)\) 。

题解

知识点:构造。

先记录每个数字出现的位置 \(pos[a[i]]\) ,随后从小到大构造:

  1. 数字没出现过,那么可以放入队列 \(qu\) ,用于补齐出现两次的数字的空位。
  2. 数字只出现了一次,假设出现在 \(a_i\) ,那么令 \(p_i = q_i = a_i\) 是最优的。因为 \(p_i,q_i\) 其中一个可以更小,但小的数字可能要用于填充别的地方,所以最优解是填两个相等的。
  3. 数字出现了两次,假设出现在 \(a_i = a_j = a\) ,那么令 \(p_i = q_j = a\) ,设 \(qu\) 里队首元素为 \(x\) ,令 \(q_i = p_j = x\) 。因为是从小到大构造,所以 \(qu\) 里的元素一定是比 \(a\) 小的,所以可以用来填充空位;如果队空,则无解。
  4. 数字出现三次及以上,无解。

时间复杂度 \(O(n)\)

空间复杂度 \(O(n)\)

代码

#include <bits/stdc++.h>
#define ll long long

using namespace std;

int a[200007];
int p[200007], q[200007];
vector<int> pos[200007];
bool solve() {
    int n;
    cin >> n;
    for (int i = 1;i <= n;i++) cin >> a[i], pos[i].clear();
    for (int i = 1;i <= n;i++) pos[a[i]].push_back(i);
    queue<int> qu;
    for (int i = 1;i <= n;i++) {
        if (pos[i].size() > 2) return false;
        if (pos[i].size() == 0) qu.push(i);//空闲数字放入队列
        else if (pos[i].size() == 1) {
            p[pos[i][0]] = i;
            q[pos[i][0]] = i;
        }//可以用小的但不是最优的
        else {
            if (qu.empty()) return false;//没有空闲的小的数字,无解
            p[pos[i][0]] = i;
            p[pos[i][1]] = qu.front();
            q[pos[i][0]] = qu.front();
            q[pos[i][1]] = i;
            qu.pop();
        }
    }
    cout << "YES" << '\n';
    for (int i = 1;i <= n;i++) cout << p[i] << " \n"[i == n];
    for (int i = 1;i <= n;i++) cout << q[i] << " \n"[i == n];
    return true;
}

int main() {
    std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int t = 1;
    cin >> t;
    while (t--) {
        if (!solve()) cout << "NO" << '\n';
    }
    return 0;
}

D

题意

给一个长为 \(n\) 的排列,每次可以选择两个数交换,问最少交换几次可以使得排列逆序数为 \(1\) 。

题解

知识点:枚举,数学。

关于这类排列的题,都可以先进行一个构造,连接所有 \(i \to a[i]\) ,图中会形成若干个环,称为置换环。例如 \(2,3,4,1,5\) ,可以得到 \(1,2,3,4\) 构成的环和 \(5\) 构成的环( \(5\) 是自环)。

我们进行一次交换操作 \((i,j)\),将使得 \(i \to a_i,j \to a_j\) 两条边变成 \(i \to a_j,j \to a_i\) 。这个操作在图中可以做到以下两个结果之一:

  1. 一个环被裂解成两个环
  2. 两个环被合并成一个环

前提是不破坏相对元素的位置,例如 \(1,3,2,4\) 环不可能分解成 \(1,2\) 和 \(3,4\) 环;\(1,2\) 和 \(3,4\) 环也不可能合并成 \(1,3,2,4\) 环。

举个例子,我们对 \(2,3,4,1,5\) 交换 \((2,4)\) ,则排列变成 \(2,1,4,3,5\) ,图中边 \(2 \to 3,4\to 1\) 变成 \(2 \to 1,4 \to 3\) ,即 \(1,2,3,4\) 环被拆成 \(1,2\) 和 \(3,4\) 两个环;或者交换 \((4,5)\) ,则排列变成 \(2,3,4,5,1\) ,图中边 \(4 \to 1,5 \to 5\) 变成 \(4 \to 5,5 \to 1\) ,即 \(1,2,3,4\) 和 \(5\) 环被合成为 \(1,2,3,4,5\) 环。

回到题目。题目要求的最终状态化成图后,实际上就是一组相邻元素成环,剩下的元素自环。

我们对原排列化为置换环图,假设这些环中已经有至少一组相邻元素(环中位置不一定需要相邻,因为可以通过操作使其相邻),如 \(1,4,2\) 环就有 \(1,2\) 两个相邻元素,我们可以在之后的操作中保留这组元素,把其他元素全都操作成自环即可;如果没有,那么先将元素都操作成自环,再多一次操作把一组相邻元素合并成环,如排列 \(3,4,5,2,1\) 有 \(1,3,5\) 和 \(2,4\) 环,一个相邻元素都没有。

假设 \(n\) 个元素的图中有 \(cnt\) 个环,那么如果我们需要把环中元素都操作成自环,实际上需要操作 \(n-cnt\) 次,因为每个环保留一个元素,剩下的元素都需要通过操作挪出来。再考虑相邻元素的结论,如果有相邻元素那么可以少操作一次 \(n-cnt-1\) ;否则需要多操作一次 \(n-cnt+1\) 。

环的实现可以看代码,和并查集类似但简单许多。

时间复杂度 \(O(n)\)

空间复杂度 \(O(n)\)

代码

#include <bits/stdc++.h>
#define ll long long

using namespace std;

int a[200007];
int fa[200007];

bool solve() {
    int n;
    cin >> n;
    for (int i = 1;i <= n;i++) cin >> a[i], fa[i] = -1;
    int ans = n;
    for (int i = 1;i <= n;i++) {
        if (fa[i] != -1) continue;
        int j = i;
        ans--;//一个环减一次,
        while (fa[j] == -1) {
            fa[j] = i;//环内元素的根设为i
            j = a[j];
        }
    }
    bool ok = 0;
    for (int i = 1;i <= n - 1;i++) ok |= fa[i] == fa[i + 1];//环内有一队相邻元素,可以少操作一次
    cout << ans + (ok ? -1 : 1) << '\n';
    return true;
}

int main() {
    std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int t = 1;
    cin >> t;
    while (t--) {
        if (!solve()) cout << -1 << '\n';
    }
    return 0;
}

标签:qu,842,int,复杂度,元素,pos,long,Codeforces,Div
From: https://www.cnblogs.com/BlankYang/p/17031203.html

相关文章

  • 1.6 vp Polynomial Round 2022 (Div. 1 + Div. 2, Rated, Prizes!)
    A-AddPlusMinusSign题意:给出01字符串,可以在每两个字符中间任意添加‘+’,‘-’。最后要使表达式的绝对值最小思路:设表达式的值为\(cnt\),若当前\(cnt\)大于\(0\),不管......
  • Codeforces Round #842 (Div. 2) A-C, 补D
    A.GreatestConvex题意:给定一个k,求一个小于k的数x,使得x!+(x-1)!是k的倍数分析:题目已经给出提示:y!=y⋅(y−1)!,输出n-1cout<<n-1<<endl......
  • Codeforces Round #842 (Div. 2) A-D题解
    比赛链接A、GreatestConvex非常的简单。根据样例直接猜是输出\(n-1\).上一个\(Python\)代码。T=int(input())whileT>0:T-=1n=int(input())......
  • B. Quick Sort【Codeforces Round #842 (Div. 2)】
    B.QuickSortYouaregivenapermutation【排列】†\(p\)oflength\(n\)andapositiveinteger\(k≤n\).Inoneoperation,you:Choose\(k\)distinctelement......
  • Codeforces Contest 1616
    A.IntegerDiversity直接用个map贪心,如果有相同的就反向即可。B.MirrorintheString这道题洛谷的翻译锅了,所以建议去看原题。考虑这样一个字符串baacc,那么答案显......
  • 「Codeforces」寒假训练 2023 #2
    A.YetAnotherPalindromeProblem原题链接#include<bits/stdc++.h>usingnamespacestd;typedeflonglongll;constintN=1e5+10;intt;intn;inta[N];i......
  • Codeforces Round #839 (Div. 3)题解
    C.DifferentDifferences(贪心)题意​ 给定\(k\),\(n\)\((2\lek\len\le40)\)。从\([1-n]\)中不重复地任选\(k\)个数组成一个数组,使这个数组的差分数组中不同的......
  • Educational Codeforces Round 11
    EducationalCodeforcesRound11https://codeforces.com/contest/660A.Co-primeArray\(1\)与任何数的\(gcd\)都为\(1\),直接在不符合条件的两点间塞就可以了#inc......
  • 1.4 vp Codeforces Round #838 (Div. 2)
    A-DivideandConquer题意:给出序列a,设b为a中元素总和。你可以选择a中任意元素,将它除以二(向下取整)。问最少需要多少次可以使b为偶数思路:将a划分为奇偶两个集合。a中偶数......
  • LOJ #2842. 「JOISC 2018 Day 4」野猪
    题面传送门考试的时候只想到处理\(O(1)\)的边没想到维护\(O(1)\)的路径。首先如果没有可以退一步的限制显然就是相邻两点的最短路之和。退一步的限制想到点边互换。与处......