Codeforces Round #765 (Div. 2)题解
目前补到C
A. Ancient Civilization
题目描述:给你\(n\)个长度为\(l\)的二进制数组\(a\),这些二进制数以十进制的形式给你,让你求一个最小的\(l\)位二进制数\(x\),定义\(d(x , y)\)表示两个数字二进制表示下不同位的个数,如1001
和1100
,\(d = 2\)。求最小的\(x\)使和式\(\sum\limits_{i = 1}^{n} d(a_i , x)\)的值最小。
思路:显然将\(a_i\)的每一位拆开,若\(a_i\)的第\(j\)位的数量小于\(n\)的一半,那么对答案的贡献为0 << j
否则对答案的贡献是1 << j
。
时间复杂度:\(O(Tnl)\)
参考代码:
int n, l, a;
void solve() {
cin >> n >> l;
vector<int> cnt(l, 0);
for (int i = 1; i <= n; ++i) {
cin >> a;
for (int j = 0; j < l; ++j) cnt[j] += a >> j & 1;
}
int res = 0;
for (int i = 0; i < l; ++i) {
int dx = 2 * cnt[i] > n;
res |= dx << i;
}
cout << res << '\n';
return;
}
B. Elementary Particles
题目描述:给你一个长度为\(n\)的数组\(a\),求最长的整数\(k\),使得数组\(a\)存在两个不同的长度为\(k\)的子段\(b , c\),且\(\exists 1 \leq i \leq k\),使得\(b_i = c_i\)。
数据范围:\(1 \leq T \leq 100 , 2 \leq n \leq 1.5 \times 10^5 ,1 \leq a_i \leq 1.5 \times 10^5, \sum n \leq 3 \times 10^5\)
思路:考虑到只需要存在即可,我们可以将相同数字的下标存下来,然后遍历每一个相同的数字,若当前数字个数小于\(2\),跳过,否则枚举相邻两个相同的数字,假设其下标为\(u , v\),则其向左边最多取\(min(u , v)\)(包含当前下标),向右边最多取\(min(n - u , n - v)\)(不包含当前下标),那么最终的长度就为
对于所有的取最大值即可。注意为了不重复遍历需要进行去重。
时间复杂度:\(O(Tnlogn)\)
空间复杂度:\(O(n)\)
参考代码:
const int N = 2e5 + 5;
vector<vector<int>>g(N);
int n;
void solve() {
cin >> n;
vector<int>a(n + 1, 0);
for (int i = 1; i <= n; ++i) {
cin >> a[i];
g[a[i]].push_back(i);
}
std::sort(a.begin(), a.end());
int m = unique(a.begin(), a.end()) - a.begin();
int res = -1;
for (int i = 1; i < m; ++i) {
if (g[a[i]].size() < 2) continue;
int len = g[a[i]].size();
for (int j = 1; j < len; ++j) {
int u = g[a[i]][j - 1], v = g[a[i]][j];
int lr = min(u, v), rs = min(n - v, n - u);
res = max(res, lr + rs);
}
}
cout << res << '\n';
for (int i = 1; i < m; ++i) g[a[i]].clear();
return;
}
C. Road Optimization
题目描述:给你一个长度为\(n\)的数组\(a\),和一个长度为\(n + 1\)的数组\(d\),(注:实际给你的只有\(n\)个,\(d_{n + 1} = l\))。其价值的计算公式为:
现让你删除其中的不超过\(k\)个元素,求\(min \{f\}\)。
数据范围:\(1 \leq n \leq 500 , 1 \leq l \leq 10^5 , 0 \leq k \leq n - 1 , 1 \leq a_i \leq 10^4\)
思路:比较显然的\(dp\),定义状态\(f_{i , j}\)表示以第\(i\)个数结尾删除\(j\)个数字后所能取得的最小值,则最终答案为:
考虑如何转移,假设枚举\((i , j]\)表示要删除该区间内的所有元素,则此时区间对答案的贡献为\((d_{j + 1} - d_i) * a_i\)。则转移方程为:
时间复杂度:\(O(n^2k)\)
参考代码:
int n, l, k;
void solve() {
cin >> n >> l >> k;
vector<int>d(n + 2, 0), a(n + 1, 0);
for (int i = 1; i <= n; ++i) cin >> d[i];
for (int i = 1; i <= n; ++i) cin >> a[i];
d[n + 1] = l;
vector<vector<int>>f(n + 1, vector<int>(k + 1, 0x3f3f3f3f));
int res = INT_MAX;
f[0][0] = 0;
for (int i = 1; i <= n; ++i) {
for (int j = i; j <= n; ++j) {
int len = j - i;
for (int r = 0; r + len <= k; ++r) {
f[j][r + len] = min(f[j][r + len], f[i - 1][r] + (d[j + 1] - d[i]) * a[i]);
}
}
}
for (int i = 0; i <= k; ++i) res = min(res, f[n][i]);
cout << res << '\n';
return;
}
作者:cherish.
出处:https://home.cnblogs.com/u/cherish-/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。