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值。