Good Bye 2021: 2022 is NEAR
A - Integer Diversity
题目大意
给定一个数组, 每次可以选择任意长度的字串取反, 问最后能有多少不同的数字
思路
很简单, 用set
记录每一个值是否出现过, 没有就插入, 有就取反然后插入
代码
#include <iostream>
#include <set>
using namespace std;
int main() {
int T;
cin >> T;
while (T --) {
int n;
cin >> n;
set<int> s;
while (n --) {
int x;
cin >> x;
if (s.count(x)) s.insert(-x);
else s.insert(x);
}
cout << s.size() << endl;
}
return 0;
}
B - Mirror in the String
题目大意
给定一个字符串, 找一个前缀, 使其前缀和前缀反串的字典序最小
思路
首先, 选择的前缀一定是不增的
但是如果开始有两个以上的相同字符, 那么必然是取一个就好
否则, 依次向后查找, 直到遇到第一个更大的字符
代码
#include <iostream>
#include <set>
#include <algorithm>
using namespace std;
int main() {
int T;
cin >> T;
while (T --) {
int n;
cin >> n;
string str;
cin >> str;
if (n == 1 || str[0] == str[1]) cout << str[0] << str[0] << endl;
else {
int i = 0;
while (i < str.length() && str[i + 1] <= str[i]) i ++;
string a = str.substr(0, i + 1);
cout << a;
reverse(a.begin(), a.end());
cout << a << endl;
}
}
return 0;
}
C - Representative Edges
题目大意
给定一个长度为n
的数组, 问最少需要改变多少数字, 可以使任意的l < r
满足 \(a_l + a_{l + 1} + \ldots + a_r = \frac{1}{2}(a_l + a_r) \cdot (r - l + 1)\)
思路
是在看过样例之后发现, 最后的结果总是变为一个等差数列
开始想, 是否可以枚举起点
和公差
, 但是存在精度问题
于是, n
是很小的, 直接三重枚举, 判断在i
和j
之间有多少k
满足 \((a_k - a_i) \cdot (k - j) == (a_k - a_j) \cdot (k - i)\)
当然也要化除为乘
代码
#include <iostream>
#include <set>
#include <algorithm>
using namespace std;
int n;
int a[100];
int main() {
int T;
cin >> T;
while (T --) {
cin >> n;
for (int i = 1; i <= n; i ++) cin >> a[i];
int ans = 1;
for (int i = 1; i <= n; i ++)
for (int j = i + 1; j <= n; j ++) {
int cnt = 0;
for (int k = 1; k <= n; k ++)
if (k == i || k == j || (a[k] - a[i]) * (k - j) == (a[k] - a[j]) * (k - i))
cnt ++;
ans = max(ans, cnt);
}
cout << n - ans << endl;
}
return 0;
}
D - Keep the Average High
题目大意
给定一个长度为n的数组, 在其中选择最多的下标使得, 任意l < r
满足
- 区间内至少有一个数没有被选择
- 或者, 总和大于
长度 * X
思路
不知道为什么就想到DP了
定义一个数组f[N][2]
, 表示到当前位置, 当前位置选或不选的最大结果数
状态转移好像有些不清晰了
/*
- 首先当前位置不选的话
- 上一个位置选和不选都可以, 取最大值
- 当前位置选
- 上一个位置不选是可以的
写了几次发现, 当前位置只会和前两个位置产生转移, 再前面就不会影响了- 转移的条件必然是和上一个位置的和大于
2 * X
- 如果当前位置大于
X
, 那么上一个位置就是可选的, 这里为什么不讨论上二个是因为 选上一个已经讨论过是否选上二个了 - 如果是上一个位置大于
X
, 那么必须注意这三个位置的和是否也是大于3 * X
- 这里首先是可以从上二个不选转移
- 然后就是大于
3 * X
的话, 上二个也是可以被选择的
这里有个技巧是多判断一个, 然后答案直接取多判断那个不取的情况
*/
代码
#include <iostream>
#include <set>
#include <algorithm>
using namespace std;
const int N = 5e4 + 10;
int n, x;
int a[N];
int f[N][2];
int main() {
int T;
cin >> T;
while (T --) {
cin >> n;
for (int i = 1; i <= n; i ++) cin >> a[i];
cin >> x;
f[1][0] = 0, f[1][1] = 1;
for (int i = 2; i <= n + 1; i ++) {
f[i][0] = max(f[i - 1][0], f[i - 1][1]);
f[i][1] = f[i - 1][0] + 1;
if (a[i] >= x && a[i] + a[i - 1] >= 2 * x) f[i][1] = max(f[i][1], f[i - 1][1] + 1);
else {
if (a[i - 1] >= x && a[i] + a[i - 1] >= 2 * x) {
if (i == 2) f[i][1] = 2;
else {
f[i][1] = max(f[i][1], f[i - 2][0] + 2);
if (a[i - 2] + a[i - 1] >= 2 * x && a[i - 2] + a[i - 1] + a[i] >= 3 * x)
f[i][1] = max(f[i][1], f[i - 2][1] + 2);
}
}
}
}
cout << f[n + 1][0] << endl;
}
return 0;
}