A - 小苯的九宮格
#include <bits/stdc++.h>
using namespace std;
int main(){
vector<int> a(11);
for(int i = 1; i <= 9; i ++) cin >> a[i];
string s;
cin >> s;
for(auto i : s)
cout << a[i - '0'];
return 0;
}
B - 小苯的好陣列
如果原陣列不是好陣列,則原陣列的任意子序列都一定不是好陣列。所以如果原陣列是好陣列,原陣列就是最長的子序列。
#include <bits/stdc++.h>
using namespace std;
using vi = vector<int>;
int main(){
ios::sync_with_stdio(false), cin.tie(nullptr);
int n;
cin >> n;
vi a(n);
for(auto & i : a) cin >> i;
if(is_sorted(a.begin(), a.end()))
cout << 0;
else
cout << n;
}
C - 小苯的數字合併
最優解一定是把字首合併成一個或者把字尾合併成一個。所以可以提前字首和預處理一下,然後列舉字首或字尾的長度。
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
#define int long long
using vi = vector<int>;
i32 main(){
ios::sync_with_stdio(false), cin.tie(nullptr);
int n;
cin >> n;
vi a(n);
for(auto & i : a) cin >> i;
vi preMax(n), preMin(n), pre(n);
preMax[0] = preMin[0] = pre[0] = a[0];
for(int i = 1; i < n; i ++) {
preMax[i] = max(preMax[i - 1], a[i]);
preMin[i] = min(preMin[i - 1], a[i]);
pre[i] = pre[i - 1] + a[i];
}
vi sufMax(n), sufMin(n), suf(n);
sufMax[n - 1] = sufMin[n - 1] = suf[n - 1] = a[n - 1];
for(int i = n - 2; i >= 0; i --) {
sufMax[i] = max(sufMax[i + 1], a[i]);
sufMin[i] = min(sufMin[i + 1], a[i]);
suf[i] = suf[i + 1] + a[i];
}
int res = sufMax[0] - sufMin[0];
for(int i = 1; i < n; i ++)
res = max(res, max(preMax[i - 1], suf[i]) - min(preMin[i - 1], suf[i]));
for(int i = n - 2; i >= 0; i --)
res = max(res, max(sufMax[i + 1], pre[i]) - min(sufMin[i + 1], pre[i]));
cout << res << "\n";
return 0;
}
D - 小苯的排列構造
首先,如果合法,則\(a_{i-1}\)一定是\(a_i\)的約數。
然後可以得到一個結論:如果若干個數\(x_j\)滿足\(\gcd(a_{i-1},x_j) = a_i\),則第\(i\)位填誰沒有影響。所以可以貪心的選擇最小值,我們可以用雙端佇列來維護當前剩下了哪些數。
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using vi = vector<int>;
i32 main(){
ios::sync_with_stdio(false), cin.tie(nullptr);
int n;
cin >> n;
vi a(n), p(n);
for(auto & i : a) cin >> i;
deque<int> q;
p[0] = a[0];
for(int i = 1; i <= n; i ++)
if(i != p[0]) q.push_back(i);
for(int i = 1; i < n; i ++) {
if(a[i-1] % a[i] != 0) {
cout << "-1\n";
return 0;
}
int fail = 0;
while(gcd(a[i - 1], q.front()) != a[i]) {
q.push_back(q.front()), q.pop_front();
fail ++;
if(fail > q.size()) {
cout << "-1\n";
return 0;
}
}
p[i] = q.front(), q.pop_front();
}
for(auto i : p) cout << i << " ";
return 0;
}
E/F - 小苯的01揹包
這題和 普通揹包的最大區別就是,普通揹包選的物品越多,總體積和總價值一定遞增,但是本題是遞減。
考慮到依舊是求解最大價值,我們可以列舉價值然後求解最小體積。
我們列舉了價值\(s\),物品\(i\)能夠被選擇的條件是\((s \& a_i) = s\)。對於所有可以被選擇的物品,我們一定是全選最優。
這樣的話,對於easy版本,我們可以暴力的列舉價值就好了。
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using vi = vector<int>;
const int N = (1 << 11) - 1;
i32 main(){
ios::sync_with_stdio(false), cin.tie(nullptr);
int n, k;
cin >> n >> k;
vi v(n), w(n);
for(int i = 0; i < n; i ++)
cin >> v[i] >> w[i];
for(int i = N, tmp; i > 0; i --) {
tmp = N;
for(int j = 0; j < n; j ++)
if((i & w[j]) == i) tmp &= v[j];
if(tmp <= k) {
cout << i << "\n";
return 0;
}
}
cout << "0\n";
return 0;
}
對於hard 版本,我們無法再列舉價值,我麼可以考慮試填法。
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using vi = vector<int>;
const int N = (1 << 11) - 1;
i32 main(){
ios::sync_with_stdio(false), cin.tie(nullptr);
int n, k;
cin >> n >> k;
vi v(n), w(n);
for(int i = 0; i < n; i ++)
cin >> v[i] >> w[i];
int res = 0;
for(int i = 30; i >= 0; i --){
int tryRes = res | (1 << i), tmp = 0x7fffffff;
for(int j = 0; j < n; j ++)
if((tryRes & w[j]) == tryRes) tmp &= v[j];
if(tmp <= k) res = tryRes;
}
cout << res << "\n";
return 0;
}