Contestant. Rank 1335. Rating +80.
A. MEXanized Array
题意
给定三个整数 \(n, k, x\),构造一个长为 \(n\) 的数组,满足 \(MEX = k\),最大值不超过 \(x\)。
输出数组总和的最大值。无法构造输出 \(-1\)。
思路
首先,如果 \(MEX\) 大于数组的长度,或者大于数组的最大值 \(+ 1\),那么就无法构造。
否则,我们就只需对 \(MEX\) 和最大值的大小关系进行特判即可。
我们先依次填入 \(0, 1, 2, \ldots, k - 1\),然后剩余的都填上最大值。如果最大值是 \(MEX\),那么我们应该填上 最大值 $ - 1$。
时间复杂度:\(O(1)\)
对应AC代码
#define chatgpt3_5 "bits/stdc++.h"
#define chatgpt4 "bits/extc++.h"
#include chatgpt3_5
using namespace std;
//#define FLOATING_OCEAN
#define int long long
#define pii pair<int, int>
#define pipi pair<pii, pii>
#define tpi tuple<int, int, int>
#define fs first
#define sc second
#define pb emplace_back
#define ep emplace
#define rall(x) x.rbegin(),x.rend()
#define all(x) x.begin(),x.end()
const int N = 1e6 + 10, M = 2e5 + 10, mod = 1e9 + 7, inf = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-9, PI = acos(-1);
void solve() {
int n, k, x;
cin >> n >> k >> x;
if(k > n || k > x + 1){
cout << -1 << '\n';
return;
}
int sum = 0;
for(int i=0;i<k;i++) sum += i;
sum += (n - k) * (x - (x == k ? 1 : 0));
cout << sum << '\n';
}
signed main() {
# ifdef FLOATING_OCEAN
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
# endif
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
// init();
int t = 1;
cin >> t;
while (t--) solve();
}
签到签到
B. Friendly Arrays
题意
给定一个长为 \(n\) 的序列 \(a\),以及一个长为 \(m\) 的序列 \(b\),定义一次操作为选定任意一个 \(b_j\),然后对所有 \(i \in [1, n]\),执行 \(a_i = a_i | b_j\)。
输出任意次操作后,序列 \(a\) 所有数的异或和的最小值和最大值。
思路
首先,如果序列 \(a\) 长为偶数,那么执行一次操作后,\(b_j\) 上所有为 \(1\) 的位置都会因为异或而变成 \(0\),从而可以发现操作次数越多,异或和越小。
那么这个时候最大值就是操作前的异或和,最小值就是将所有 \(b_j\) 都操作一遍后的异或和。
如果序列 \(a\) 长为奇数,那么执行一次操作后,\(b_j\) 上所有为 \(1\) 的位置都会因为异或而变成 \(1\),从而可以发现操作次数越多,异或和越大。
那么相反的,此时最小值就是操作前的异或和,最大值就是将所有 \(b_j\) 都操作一遍后的异或和。
那么不妨直接把这两个答案算出来,然后输出最小值和最大值即可。
时间复杂度:\(O(n)\)
对应AC代码
#define chatgpt3_5 "bits/stdc++.h"
#define chatgpt4 "bits/extc++.h"
#include chatgpt3_5
using namespace std;
//#define FLOATING_OCEAN
#define int long long
#define pii pair<int, int>
#define pipi pair<pii, pii>
#define tpi tuple<int, int, int>
#define fs first
#define sc second
#define pb emplace_back
#define ep emplace
#define rall(x) x.rbegin(),x.rend()
#define all(x) x.begin(),x.end()
const int N = 1e6 + 10, M = 2e5 + 10, mod = 1e9 + 7, inf = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-9, PI = acos(-1);
void solve() {
int n, m;
cin >> n >> m;
vector<int> a(n + 1);
int ans1 = 0, ans2 = 0;
for(int i=1;i<=n;i++) {
cin >> a[i];
ans1 ^= a[i];
}
int w = 0;
for(int i=1;i<=m;i++) {
int x;
cin >> x;
w |= x;
}
for(int i=1;i<=n;i++){
ans2 ^= (a[i] | w);
}
if(ans1 > ans2) swap(ans1, ans2);
cout << ans1 << ' ' << ans2 << '\n';
}
signed main() {
# ifdef FLOATING_OCEAN
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
# endif
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
// init();
int t = 1;
cin >> t;
while (t--) solve();
}
有意思的思维题
C. Colorful Table
题意
给定一个长为 \(n\) 的序列 \(a, a[i] \leq k\),对于一个 \(n \times n\) 的矩阵 \(b\),有 \(b[i][j] = \min(a[i], a[j])\)。
对于 \(x \in [1, k]\),输出将 \(b[i][j] = x\) 的所有方格包含在里面的最小矩形的长宽之和。
思路
首先,得到的矩阵是对称的,所以最后的答案肯定是一个正方形的边长 \(\times 2\)。
其次,因为有取最小值操作,所以我们不妨从小到大枚举所有颜色,用 \(\mathtt{set}\) 维护值大于等于当前颜色的下标集合。
那么,对于这个颜色,我们需要的答案就是最大的下标和最小的下标的距离 \(\times 2\)。
时间复杂度:\(O(n \log n)\)
对应AC代码
#define chatgpt3_5 "bits/stdc++.h"
#define chatgpt4 "bits/extc++.h"
#include chatgpt3_5
using namespace std;
//#define FLOATING_OCEAN
#define int long long
#define pii pair<int, int>
#define pipi pair<pii, pii>
#define tpi tuple<int, int, int>
#define fs first
#define sc second
#define pb emplace_back
#define ep emplace
#define rall(x) x.rbegin(),x.rend()
#define all(x) x.begin(),x.end()
const int N = 1e6 + 10, M = 2e5 + 10, mod = 1e9 + 7, inf = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-9, PI = acos(-1);
void solve() {
int n, k;
cin >> n >> k;
vector<int> a(n), ans(k);
vector<vector<int>> pos(k);
set<int> s;
for(int i = 0;i < n;i++){
cin >> a[i];
a[i] --;
pos[a[i]].push_back(i);
s.insert(i);
}
for(int i = 0;i < k;i++) {
if (pos[i].empty()) continue;
int x = *s.rbegin(), y = *s.begin();
ans[i] = x - y + 1;
for (auto it : pos[i]) s.extract(it);
}
for(auto e : ans) cout << e * 2 << ' ';
cout << '\n';
}
signed main() {
# ifdef FLOATING_OCEAN
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
# endif
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
// init();
int t = 1;
cin >> t;
while (t--) solve();
}
其实很显然,但我也不知道为啥做了好一会儿(x
D. Prefix Purchase
题意
给定长度为 \(n\) 的序列 \(a, c\),其中序列 \(a\) 的初始值都是 \(0\)。
对于第 \(i\) 种支付,可以通过支付 \(c_i\) 个硬币,来使 \([1, i]\) 内所有 \(a_i\) 都加上 \(1\)。
现在,在硬币最多有 \(k\) 个的条件下,输出字典序最大的 \(a\)。
思路
首先,为了让第一个数尽可能大,我们一定会尽可能多使用价格低的。
那么,我们先全用价格最低的硬币,然后考虑用价格高但范围更大的硬币替换。
显然,我们肯定先用小的替换,这样代价更小,那么我们只需贪心地从小到大枚举所有支付方式,然后只使用能让范围进一步扩大地方式即可。
时间复杂度:\(O(n \log n)\)
对应AC代码
#define chatgpt3_5 "bits/stdc++.h"
#define chatgpt4 "bits/extc++.h"
#include chatgpt3_5
using namespace std;
//#define FLOATING_OCEAN
#define int long long
#define pii pair<int, int>
#define pipi pair<pii, pii>
#define tpi tuple<int, int, int>
#define fs first
#define sc second
#define pb emplace_back
#define ep emplace
#define rall(x) x.rbegin(),x.rend()
#define all(x) x.begin(),x.end()
const int N = 1e6 + 10, M = 2e5 + 10, mod = 1e9 + 7, inf = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-9, PI = acos(-1);
void solve() {
int n;
cin >> n;
vector<int> a(n + 1), d(n + 2);
map<int, int> mp;
for (int i = 1; i <= n; i++) {
cin >> a[i];
mp[a[i]] = i;
}
int k;
cin >> k;
int v = 0, pos = 0, pcnt = inf;
for (auto [x, y]: mp) {
if (y <= pos) continue;
int cnt = min(pcnt, k / (x - v));
d[pos + 1] += cnt;
d[y + 1] -= cnt;
k -= cnt * (x - v);
pcnt = cnt;
v = x, pos = y;
}
for (int i = 1; i <= n; i++) {
d[i] += d[i - 1];
cout << d[i] << ' ';
}
cout << '\n';
}
signed main() {
# ifdef FLOATING_OCEAN
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
# endif
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
// init();
int t = 1;
cin >> t;
while (t--) solve();
}
哎,贪心