Codeforces Round #740 (Div. 2) A C

A - Simply Strange Sort

题意

给你定义一个 f 操作,f(i) 为如果 a i > a i + 1 a_i>a_{i+1} ai>ai+1就交换两个数

然后给定操作 i,如果 i 是奇数则对所有的奇数下标的数都做f操作;如果 i 是偶数对所有的偶数下标都做 f 操作

n为奇数

给定数列为n的全排列

问多少次操作会使得数列递增

题解

一开始还以为是什么根据这个数所在的位置和应该所在的位置的,结果估摸一下数据范围,应该可以暴力

Code

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <map>
#include <vector>
#include <set>
#include <queue>
#include <stack>
#include <sstream>
#include <unordered_map>
#define ll long long
#define ull unsigned long long
#define re return
#define pb push_back
#define Endl "\n"
#define endl "\n"
#define x first
#define y second

using namespace std;

typedef pair<int, int> PII;

const int N = 1e3 + 10;

int dx[4] = {-1,0,1,0};
int dy[4] = {0,1,0,-1};

int T;
int n;
int a[N];
int b[N];

bool pd(){
    for (int i = 1; i <= n; i++){
        if(b[i] != a[i])
            return 0;
    }
    return 1;
}

void f(int x){
    if(x % 2 != 0){
        for (int i = 1; i <= n - 2; i += 2){
            if(a[i] > a[i + 1]){
                swap(a[i], a[i + 1]);
            }
        }
    }
    else{
        for (int i = 2; i <= n - 1; i += 2){
            if(a[i] > a[i + 1]){
                swap(a[i], a[i + 1]);
            }
        }
    }
}

void debug(){
    for (int i = 1; i <= n; i++){
        cout << a[i] << " ";
    }
    cout << Endl;
}

int main(){
    for (int i = 1; i <= 1000; i++){
        b[i] = i;
    }

    cin >> T;
    while(T--){
        cin >> n;
        for (int i = 1; i <= n; i++){
            cin >> a[i];
        }

        int i = 0;
        while(!pd()){
            f(++i);
            // debug();
        }
        cout << i << endl;
    }
}

B - Charmed by the Game

没看懂题,代补

C - Deep Down Below

题意

给n个洞,第 i 个洞里有 ki 个怪物,击败怪物需要能力值大于其护甲值 ai,没击败一个怪物就能增加一点能力值

问能把所有洞都闯一遍的所需要的最小的初始能力值是多少

题解

首先每一个洞能闯进去,必须其到达对应的位置时的能力值必须大于此时要打的怪物的护甲值(叠甲,过qwq)

而每打一个就会能力值增加1,所以我们不妨把能力的贡献值与其对应的护甲值相抵消,也就是假设没有这个+1能量的条件,只有一开始的能力值大于这个洞穴中的最大的那个自然就能把这个洞都打通。所以每一个洞的所需的至少的能力值就是 p w e r i = m a x ( a k i , i − j + 1 ) + 1 , j ∈ [ 1 , k i ] pwer_i=max(a_{k_i,i} -j+1)+1,j\in [1,k_i] pweri=max(aki,ij+1)+1,j[1,ki],加一是要严格大于

那么我们也不能完全忽视掉这个+1的条件,每当我们打完一个洞,此时获得的能量加成就是 k i k_i ki

我是这么想的,如果能力值足够大,那么肯定所有的洞都能打通。如果我有一个答案他慢慢成长为所有的洞能够打的值,也是可以的,那么怎么安排呢?

那么能力值就成为一个区间:

在这里插入图片描述

ans为最优解。如果足够大,那么就能很轻松的打通,如果不行,那肯定不行(废话

那这像什么?这不就是二分的区间吗。而且是合法的解在右边,找右边的左端点,就用我私藏的二分模版1啊

那还有一个问题比赛的时候我还在考虑,那就是攻打顺序的问题。

肯定知道不能暴力枚举啊。

那我为什么不想按能攻进去的能力值从小到大打呢。这样前面的我能尽可能的升级(升能力值),毕竟能力越大,后面越能打

注意能力的取值不一定是每个洞所需要的那个值,也就是二分的条件不是下标,看代码就明白 了

Code

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <map>
#include <vector>
#include <set>
#include <queue>
#include <stack>
#include <sstream>
#include <unordered_map>
#define ll long long
#define ull unsigned long long
#define re return
#define pb push_back
#define Endl "\n"
#define endl "\n"
#define x first
#define y second

using namespace std;

typedef pair<ll, ll> PII;

const int N = 1e5 + 10;

int dx[4] = {-1,0,1,0};
int dy[4] = {0,1,0,-1};

int T;
int n;
PII a[N]; // 我觉得应该用ll,但是我没实验int

bool check(int id){
    // ll pow = a[id].y + a[id].x;
    ll pow = id;
    for (int i = 1; i <= n; i++){
        // if(i == id)
        //     continue;
        if(pow < a[i].x)
            return 0;
        else
            pow += a[i].y;
    }
    return 1;
}

int main(){
    cin >> T;
    while(T--){
        cin >> n;
        for (int i = 1; i <= n; i++){
            ll k;
            cin >> k;
            ll maxx = 0;
            for (ll j = 1; j <= k; j++){
                ll x;
                cin >> x;
                maxx = max(maxx, x - j + 1);
            }
            a[i].x = maxx + 1; // 至少的条件
            a[i].y = k; // 打完获得的能力

            // cout << a[i].x << " " << a[i].y << Endl;
        }

        sort(a + 1, a + 1 + n);
        // for (int i = 1; i <= n; i++){
        //     cout << a[i].x << " " << a[i].y << Endl;
        // }

        int l = a[1].x;
        int r = a[n].x;

        // if(check(l)){
        //     cout << a[l].x << endl;
        //     continue;
        // }

        while(l < r){
            int mid = (l + r) >> 1;
            if(check(mid)){
                r = mid;
                // rp = a[mid].x;
            }
            else{
                l = mid + 1;
                // lp = a[mid].x;
            }
                
        }
        cout << l << endl;
        // cout << a[l].x << endl;
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值