Good Bye 2021: 2022 is NEAR
阿新 • • 發佈:2022-01-02
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;
}