Codeforces Round #840 (Div. 2) and Enigma 2022 - Cybros LNMIIT

A. Absolute Maximization

题意:给定一个数组,进行一系列操作后,找出若干次操作后可以得到的最大值与最小值的差。可以执行的操作:任选两个数,将这两个数的某个bit位进行交换。

思路:需要在若干次操作后找出最大数和最小数,而且不对交换次数进行限制,所以如果某个数的某一个bit位为1,那么最大数里这个bit为一定为1,所以可以用0跟每个数进行or运算。如果某个数的bit位为0,那么最小数的这个bit位也一定为0,而且输入数据的最大数范围∈[0, 1023],所以可以选择1023与每个数做与运算,因为1023的所有bit位全是1,做&运算可以保证如果将任何0bit位保存下来,并得到最小数。

 

#include <iostream>
#include <vector>
#include <unordered_map>
#include <map>
#include <set>
#include <string>
#include <cmath>
#include <algorithm>
#include <stack>
#include <unordered_set>
using namespace std;

typedef long long int ll;
typedef unsigned long long int ull;
typedef vector<int> vi;
typedef vector<vector<int>> vvi;
typedef vector<vector<long long int>> vvll;
typedef vector<ll> vll;
typedef vector<char> vc;

#define INT_MAX pow(2, 31) - 1
#define INT_MIN -pow(2, 31)

int main() {
    ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
    int N;
    cin >> N;
    while(N--){
        int maxx = 0, minn = (1 << 10) - 1 ,t, n;
        cin >> n;
        while (n--){
            cin >> t;
            maxx = maxx | t;
            minn = minn & t;
        }
        cout << maxx - minn << endl;
    }
    return 0;
}

总结:对位运算不熟悉,所以一开始想到是暴力破解,让每两个数进行比对,如果某个bit位存在0,1的情况,就让这个两个bit位进行交换。用log(x) / log(2) + 1可以得到当前数的二进制表示的位数,然后不断的用1去左移,去判断当前位的两个数是否满足交换条件。但是这样的交换时间复杂度有点高,时间复杂度大概是2的11次方,不一定能跑过去。针对这种题的做法还是要理解题意,才能找到针对的解法。

 

B. Incinerate

题意:给定两个长度为n的数组h和p,还有一个数k。每次将h数组中所有的数减去k,然后将k减去p中的最小的数,这个数的位置对应h中的数必须大于。问:能否将h中所有的数都变为小于等于0的数。

思路:因为每次都要找p数组中的最小数,再判定h数组中的数是否符合题意,所以先数组按p递增排序,然后对数据进行访问。被访问的元素x是h中的元素,访问x存在两种情况:k >= x, 也就是说x-k后小于0,k要减的数跟x不对应,直接找下一个数。k < x, 也就是说x在减去k后,k要减去的数,就是h数组中x位置的数,然后不断的将x减去k,也不断的更新k值,直到 k >= x或者k<=0。 如果最后k<=0并且x>0,说明k不能让这个数组中所有数<=0,输出no。如果k>0,那么继续访问下一个数。设访问的下一个数是y,刚才k在上一个数已经减去了一部分,所以这个y也要先减去刚才k减x消耗掉的数。因为题目的操作要求是:每一次操作,数组中所有的数都减去k。所以在不断更新k的过程中,设置一个sum值,表示已经用掉的k,在每次访问一个数的时候,用sum + k与这个数做比较,或者用sum与这个数做比较。

 

#include <iostream>
#include <vector>
#include <unordered_map>
#include <map>
#include <set>
#include <string>
#include <cmath>
#include <algorithm>
#include <stack>
#include <unordered_set>
using namespace std;

typedef long long int ll;
typedef unsigned long long int ull;
typedef vector<int> vi;
typedef vector<ll> vll;
typedef vector<vector<int>> vvi;
typedef vector<vector<ll>> vvll;
typedef vector<char> vc;

#define INT_MAX pow(2, 31) - 1
#define INT_MIN -pow(2, 31)

struct node{
    int h;
    int p;
};

bool cmp(struct node a, struct node b){
    return a.p < b.p;
}
int main() {
    ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
    int N;
    cin >> N;
    while (N--){
        int n, k;
        cin >> n >> k;
        vector<struct node> a(n);
        for (int i = 0; i < n; ++i){cin >> a[i].h;}
        for (int i = 0; i < n; ++i){cin >> a[i].p;}
        sort(a.begin(), a.end(), cmp);
        int sum = 0;
        bool ok = true;
        for (int i = 0; i < n; ++i){
            if (k + sum - a[i].h >= 0 || sum > a[i].h) continue;
            else{
                a[i].h -= sum;
                while(a[i].h > 0 && k > 0) {
                    a[i].h -= k; 
                    sum += k;
                    if (a[i].h > 0) k -= a[i].p;
                    else if (i < n && i != n - 1){k -= a[i + 1].p;}
                }
                if (k <= 0 && a[i].h > 0){ok = false; break;}
            }
        }
        cout << (ok ? "YES" : "NO") << endl;
    }
    return 0;
}

总结:脑子有点乱,总结不出来。这个题的关键点在于如何快速的确定当前元素能否被消除,而确定当前元素能否被消除的方法在于K值,所以当K值小于这个数的时候,就要快速的对这个数进行判断,直到这个数被消除或者消除失败。如果被消除,那么判定下一个数能否被消除,在这个过程中,K是动态变化的,因为K的改变跟最小的P有关系,所以要不断的记录新的K值。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值