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

本文详细介绍了CodeforcesRound#842(Div.2)中的三道编程题目,包括最大公约数问题、快速排序变体以及元素分解问题。针对每道题目,文章提供了思路分析、证明过程、代码实现,展示了如何运用数学和算法知识来解决这些问题。
摘要由CSDN通过智能技术生成

Codeforces Round #842 (Div. 2)

A. Greatest Convex

题目大意

给你一个整数 k k k ,已知 x ∈ [ 1 , k ) x \in [1,k) x[1,k) , 问最大的 x x x 使 x ! + ( x − 1 ) ! x! + (x - 1)! x!+(x1)! 可以被 k k k 整除

思路/证明

我们将 x ! + ( x + 1 ) ! x! + (x + 1)! x!+(x+1)! 化简得:
x ! + ( x − 1 ) ! = 1 × 2 × 3 × ⋯ × x + 1 × 2 × 3 × ⋯ × ( x − 1 ) = ( x + 1 ) × ( 1 × 2 × 3 × ⋯ × ( x − 1 ) ) x! + (x - 1)!\\ \begin{align} & = 1\times2\times3\times\dots\times x + 1\times2\times3\times\dots\times(x-1)\\ & = (x+1)\times (1\times2\times3\times\dots\times (x-1)) \end{align} x!+(x1)!=1×2×3××x+1×2×3××(x1)=(x+1)×(1×2×3××(x1))
( x + 1 ) × ( 1 × 2 × 3 × ⋯ × ( x − 1 ) ) (x+1)\times (1\times2\times3\times\dots\times (x-1)) (x+1)×(1×2×3××(x1)) 除于 k

因为 x ∈ [ 1 , k ) x \in [1,k) x[1,k) , 所以 x + 1 ∈ [ 2 , k ] x+1 \in [2,k] x+1[2,k] , 当 ( x + 1 ) = k (x+1) = k (x+1)=k 的时候, ( x + 1 ) × ( 1 × 2 × 3 × ⋯ × ( x − 1 ) ) (x+1)\times (1\times2\times3\times\dots\times (x-1)) (x+1)×(1×2×3××(x1)) 刚好被 k k k 整除

所以 x x x 的最大值为 k − 1 k-1 k1

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long int lli;
lli time_, give;
signed main()
{
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    cin >> time_;
    for(lli temp = 0 ; temp < time_ ; temp++){
        cin >> give;
        cout << give - 1 << "\n";
    }
    return 0;
}

B. Quick Sort

题目大意

给你一个排列 p = [ a 1 , a 2 … a n ] p = [a_1, a_2 \dots a_n] p=[a1,a2an] 和一个整数 k k k

你可以将在排列中选取 k ( a i , a i + 1 , a i + 2 … a i + k ) k(a_i,a_{i+1},a_{i+2}\dots a_{i+k}) k(ai,ai+1,ai+2ai+k) 个数,然后在排列p$中删掉这 k k k个数,再将这 k k k个数按照升序排列在排列 p p p的末尾

问:最少需要多少次操作可以使排列 p p p按照递增的顺序排列

思路

假设我们现在有这样一个队列:
5 3 1 4 2 5\quad\quad\quad\quad3\quad\quad\quad\quad1\quad\quad\quad\quad4\quad\quad\quad\quad2 53142
可以将上述操作理解为选 k k k 个数排好序扔到队列末尾

一个队列排好序递增一定是 1 , 2 , 3 , 4 , … , n 1,2,3,4,\dots ,n 1,2,3,4,,n

所以 1 1 1 必然是开头,所有 1 1 1之前的数都将被挪到队列末尾

同理 1 1 1 2 2 2之间的数也会被挪到队列末尾, 2 2 2 3 3 3之间的数也会被挪到队列末尾…直至队列的末尾

这样我们就能求的需要挪动的数

我们一次可以挪动 k k k个数,这样我们就可以相除算出需要的操作数了

值得注意的是,除出来的数是小数,要向上取整

代码

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int arr[N];
int total_ask,total_num, oper, need = 0, num;
signed main()
{
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    cin >> total_ask;
    while(total_ask--){
        cin >> total_num >> oper;
        for(int tem = 0 ; tem < N ; tem++) arr[tem] = 0;
        need = 0;
        for(int temp = 1 ; temp <= total_num ; temp++)
            cin >> arr[temp];
        for(int temp = 1 ; temp <= total_num ; temp++){
            if(arr[temp] == need + 1)  need++;
        }
        need = total_num - need;
        int ans = need % oper ? need / oper + 1 : need /oper;
        cout << ans << "\n";
    }
    return 0;
}

C. Elemental Decompress

题目大意

给你一个数组 a n = [ a 1 , a 2 , a 3 … a n ] a_n = [a_1,a_2,a_3\dots a_n] an=[a1,a2,a3an]

问是否存在两个队列 p p p q q q 满足一下条件

a i = m a x ( p i , q i ) i ∈ [ 0 , n ) a_i = max(p_i , q_i) \quad i \in [0,n) ai=max(pi,qi)i[0,n)

存在输出 p p p q q q

思路/证明

可以用贪心的思路求解这道题

在这个数组中,如果这个数是第一次出现,那我将它放于 p p p上,即:,第二次出现则放在 q q q上,即:,第三次则说明条件无法满足,应为两个排列无法出现三个一样的数

接下来,逐一扫描 p p p q q q排列,假设这个某个排列没有被赋上值,那么根据贪心的思想,选取一个最接近已选数的填上

即: p [ i ] = 6 p[i] = 6 p[i]=6 ,那么 q [ i ] q[i] q[i]将在可选范围内选出一个最接近 p [ i ] p[i] p[i]的数,如果找不到就说明条件无法成立

注:可以使用set来确定可选方案,更加方便,初始化的化不要全部设为0,即循环2e5来赋值,更不要memset

代码

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
int arr[N], Judge[N], p[N], q[N];
set<int>one,two;
int total_ask, total_num;
signed main()
{
    cin >> total_ask;
    while(total_ask--){
        cin >> total_num;
        for(int temp = 1 ; temp <= total_num ; temp++){
            cin >> arr[temp];
            one.insert(temp); two.insert(temp);
            Judge[temp] = p[temp] = q[temp] = 0;
        }
        int flag = 1;
        for(int temp = 1 ; temp <= total_num ; temp++){
            Judge[arr[temp]]++;
            if(Judge[arr[temp]] == 3) {flag = 0 ; break;}
            if(Judge[arr[temp]] == 1){
                p[temp] = arr[temp];
                one.erase(arr[temp]);
            }else{
                q[temp] = arr[temp];
                two.erase(arr[temp]);
            }
        }
        if(!flag) {cout << "NO\n"; continue;}
        for(int temp = 1 ; temp <= total_num ; temp++){
            if(p[temp] && q[temp]) continue;
            if(p[temp]){
                auto re = two.upper_bound(p[temp]);
                if(re == two.begin()) {flag = 0; break;}
                re--;
                q[temp] = *re;
                two.erase(re);
            }else{
                auto re = one.upper_bound(q[temp]);
                if(re == one.begin()) {flag = 0; break;}
                re--;
                p[temp] = *re;
                one.erase(re);
            }
        }
        if(!flag) {cout << "NO\n"; continue;}
        cout << "YES\n";
        for(int temp = 1 ; temp <= total_num ; temp++)
            printf("%d%c", p[temp], " \n"[temp == total_num]);
        for(int temp = 1 ; temp <= total_num ; temp++)
            printf("%d%c", q[temp], " \n"[temp == total_num]);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yyym__

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值