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

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

时间:2023-01-06 15:46:45浏览次数:80  
标签:842 int 题解 -- flag ans Div comp 数字

比赛链接

A、Greatest Convex

非常的简单。根据样例直接猜是输出 \(n - 1\).

上一个 \(Python\) 代码。

T = int(input())
while T > 0:
    T -= 1
    n = int(input())
    print(n - 1)


B、Quick Sort

题目大意是每次选 \(k\) 个,然后把他们排序后放到末尾。
那不妨这么看。每次我们先把已经有序的部分提取出来,即 \(1, 2, 3 ...\) 一直到最后一位。对于这些已经有序的部分,我们是不用进行任何操作的。而对于他们周围以及中间的无序部分,我们全部都要提取出来并排序。(无序部分的排序规则很简单,每次选未被排序的前 k 小并将其排到末尾。)那么,如果碰到不是 \(k\) 的倍数怎么办?可以发现,将已经有序的最后几位扒出来跟多余部分再排就好了。 所以答案就是无序部分的个数 \(num / k\)(向上取整)。

#include <bits/stdc++.h>
using namespace std;
#define N 1000100
int n, k; 
int a[N]; 

int main(){
    int T; cin >> T;
    while(T--){
        cin >> n >> k; 
        for(int i = 1; i <= n; i++)
            cin >> a[i];
        int now = 1, tot = 0; 
        for(int i = 1; i <= n; i++){
            if(a[i] == now){
                now++; 
                tot++; 
            }
        }
        int sum = n - tot; 
        int ans = sum / k + (sum % k != 0); 
        cout << ans << endl; 
    }
    return 0; 
}

C、Elemental Decompress

首先特判几个显然的特殊情况:

  1. 任何数字出现个数不超过 3
  2. 最大值必须出现(不能为 \(0\) 次)
  3. 最小值(即 \(1\)) 出现次数不超过 \(1\) 次。

然后考虑普通数字的出现 \(0, 1, 2\)次 情况。
对于出现一次的数字,有个显然的方法,就是两个数组都放同样的数字(自己)。可以发现这样放比起其中一个放更小的值是绝对不亏的。(不可能放更大的值对吧。)
对于出现两次的数字,我们记录下来他们出现的两个位置。然后两个数组分别设为对应值即可。
可以发现,如果有出现两次的数字,那么两个数组对应的另外一个位置就会出现空缺。那么我们肯定要在对应的那个空缺填上一个更小值。可以发现,这时候我们剩下的能填的值只有出现 \(0\) 次的数字。最优填法肯定就是每次填一个最大的小于他的数。所以把所有剩下的数字放进 \(set\) 里面,用lower_bound 查询一下是否等于begin(),如果不是,就 it--, 取得对应值。如果是,就说明没有更小值,输出 \(NO\) 即可。

#include <bits/stdc++.h>
using namespace std;
#define N 200010
int n, k; 
int a[N]; 

int vis[N];  // 每个数字的出现次数
int ans[N][2]; 
vector <int> G[N]; // 每个数字出现的位置

int main(){
//	freopen("hh.txt", "r", stdin);  
    int T; cin >> T; 
    while(T--){
        for(int i = 1; i <= n; i++){
            ans[i][0] = ans[i][1] = 0; 
            G[i].clear(); 
        }
        int maxn = 0; 
        cin >> n;
        for(int i = 1; i <= n; i++)
            cin >> a[i], maxn = max(maxn, a[i]);
        
        
        for(int i = 1; i <= maxn; i++)
            vis[i] = 0; 
        for(int i = 1; i <= n; i++){
            G[a[i]].push_back(i); 
        }
        set <int> s; 
        
        bool flag = 1; 
        for(int i = 1; i <= maxn; i++){
            sort(G[i].begin(), G[i].end()); 
            if(G[i].size() == 0) s.insert(i); 
            else if(G[i].size() == 1) ans[G[i][0]][0] = ans[G[i][0]][1] = i; 
            else if(G[i].size() == 2){
                ans[G[i][0]][0] = ans[G[i][1]][1] = i; 
            } 
            else if(G[i].size() >= 3){
                flag = 0;
                break; 
            }
        }
        if(G[n].size() == 0) flag = 0; 
        if(G[1].size() > 1) flag = 0; 
        for(int i = 1; i <= n; i++){
            if(ans[i][0] && !ans[i][1]){
                int pos = G[ans[i][0]][1];  // 二号位的 pos
                set<int>::iterator it = s.lower_bound(ans[i][0]); 
                if(it == s.begin()){
                    flag = 0; 
                    break; 
                }
                else{
                    it--; 
                    ans[i][1] = ans[pos][0] = *it; 
                    s.erase(it); 
                }
            }
        }
        if(!flag){
            puts("NO");
        }
        else{
            puts("YES"); 
            for(int i = 1; i <= n; i++)
                printf("%d ", ans[i][0]);
            cout << endl; 
            for(int i = 1; i <= n; i++)
                printf("%d ", ans[i][1]); 
            cout << endl; 

        }
    }

    return 0; 
}

D、Lucky Permutation

发现题目要求只剩下一个逆序对。
可以想到,这个剩下的逆序对肯定是原序列(称有序序列为原序列)中相邻的两个数。那么不妨先把他们排成总体有序的数列,这样子就和题目要求的情况只有一步之遥了。
考虑如何求出排成总体有序数列的最快步数。

偷懒,上 \(Tutorial\) 截图先。
666
这句话是什么意思呢,就是将序列按照下标的下标,下标的下标的下标。。。。。建成一张图。可以发现这张图就是一个个环。注意,这里是通过下标的访问建图的。而下标也就对应着这个数字本应前往的地方。因此,如果我们要进行排序,对于一个环上所有的数字,只需要在环内进行交换即可。那么,对于一个有 \(k\) 个元素的环,我们不妨以其中一个点为基准,将他沿任意固定方向一直移动(交换),那么我们只需要移动 \(k - 1\) 次便能使环上元素全部到达其应到的位置。

接下来考虑如何剩下一个逆序对。其实这个过程就是在对原序列排成整体有序时,某一对相邻元素不交换。因此,如果有任意一对相邻元素在同一个环内,我们就可以将两个元素反向移动,只需要 \(k - 2\) 步便能达到对方的应到位置,形成逆序对,故此时总答案减一。
如果没有任何一组,那么我们只能在完全排有序后将任意一组互换,故此时总答案加一。

上一个 C# 代码。

using System;

namespace CodeForces
{
    class NewBaseType
    {   
        public static void Main(string[] args)
        {
            var T = Convert.ToInt32(Console.ReadLine()); 
            while(T > 0){
                T--; 
                var n = Convert.ToInt32(Console.ReadLine()); 
                int[] a = new int[n + 10]; 
                string[] tmp = Console.ReadLine().Split(); 
                
                for(int i = 0; i < tmp.Count(); i++){
                    a[i] = Convert.ToInt32(tmp[i]) - 1; 
                }

                int[] comp = new int[n + 10]; 
                int id = 1, ans = 0; 
                for(int i = 0; i < n; i++){
                    if(comp[i] != 0) continue; 
                    int v = i; 
                    while(comp[v] == 0){
                        comp[v] = id; 
                        v = a[v]; 
                        ans++; 
                    }
                    id++; 
                    ans--; 
                }

                bool flag = false; 
                for(int i = 0; i < n - 1; i++){
                    if(comp[i] == comp[i + 1]){
                        flag = true; 
                        break; 
                    }
                }

                if(flag == true){
                    Console.WriteLine(ans - 1); 
                }
                else Console.WriteLine(ans + 1); 


            }
        }
    }


}

标签:842,int,题解,--,flag,ans,Div,comp,数字
From: https://www.cnblogs.com/wondering-world/p/17030453.html

相关文章

  • USACO Au题解
    T1一眼背包,但是很怪考虑设dp[i][j][k]表示前i个物品还剩j个月饼还剩k个冰激凌。$O(n^4)$显然。转移O(n)枚举用钱还是优惠券。瓶颈在于冰激凌的优惠。考虑如何把这一......
  • idea 内存参数修改不生效问题解决 VM参数设置不生效解决
    提示:在idea的工具栏Help->EditCustomVMOptions内修改 对应参数-Xmx1024m后重启无效的再看下面的方法 问题:ieda的默认内存大小是1024M当我开多个工......
  • PIP 更新后不能使用的使用 提示: No module named 'pip'问题解决
    1、问题引入   正确安装Python以后,Python和PIP都可以正常使用。在使用pip安装其他库的时候,提示PIP版本过低,建议更新,结果更新时发生错误,导致PIP不能被识别,具体如下图......
  • B. Quick Sort【Codeforces Round #842 (Div. 2)】
    B.QuickSortYouaregivenapermutation【排列】†\(p\)oflength\(n\)andapositiveinteger\(k≤n\).Inoneoperation,you:Choose\(k\)distinctelement......
  • 【题解】P2305 [NOI2014] 购票
    题意给定一棵边带权且以\(1\)为根的树,从后代结点\(u\)跳到祖先结点\(v\)的代价为\(dp_u+q_u\),其中\(p_u,q_u\)是给定的常数,\(d\)是\(u,v\)的树上距离。要......
  • BalticOI 2004 Sequence 题解
    题目链接在这里~对于序列\(\{a\}\),把每一个\(a_i\)减去一个\(i\),得到\(\{a'\}\)序列\(\{b\}\)同理。因为\(b_1<b_2<...<b_n\),故\(b_1'\leqslantb_2'\leqslant...\leqs......
  • ATC简单题解(不定时更新
    ABC129前三题略D.lamp虽然数据范围不大,但也没法暴力check,可以考虑分别维护每行(每列)障碍物的纵(横)坐标,可以考虑到插入std::vector中,然后对于每一个点查找横竖方向上的......
  • CF893D Credit Card 题解
    简要题意:你有一张信用卡,\(n\)天有\(n\)个操作,每次操作给定一个\(x\),如果\(x\)是\(0\)那么银行会查询信用卡里的金额,要保证金额是非负数;否则你卡里的金额会变化\(x......
  • 安徽农业大学寒假训练赛1题解
    D#include<bits/stdc++.h>usingnamespacestd;charg[10][10];intmain(){for(inti=1;i<=5;i++)scanf("%s",g[i]+1);//这样可以保证下标都从1......
  • 题解 : Luogu P2197 【模板】nim 游戏
    题目链接:link结论如果$a_1\oplusa_2\oplus...\oplusa_n\not=0$,则先手必胜证明操作到最后时,每堆石子数都是\(0\),\(0\oplus0\oplus...\oplus0=0......