「賽後總結」20200906
阿新 • • 發佈:2020-09-06
得分情況
預計得分:\(100 + 100 + 0 \sim 100 = 200 \sim 300\)。
實際得分:\(100 + 100 + 60 = 260\)。
考場上
開 T1,題目有點難讀懂,讀了一遍放過去了。
開 T2,讀了一遍題感覺需要的用到二分答案,這是一個 log,check
裡可能需要用到 upper_bound
或者 lower_bound
,共兩個 log,沒思路了,過。
開 T3,嚴格次短路,不會,寫玄學演算法希望多騙點分。
回去看 T1,看懂了題,發現是個 sb 題。寫完 T1,在想暴力怎麼寫,寫出來了暴力,拍上了。去想 T2。
感覺需要個 DP,想 DP 怎麼寫,大樣例來了,T1 過了大樣例就不拍了,T2 想了一個不知道對錯的 DP,過了大樣例。
寫了個暴力,然後對拍,出了兩次鍋,一次是造資料的鍋了,一次是暴力輸入順序反了。。
T1咒語
每一位是獨立的,我們要讓每一位的差異儘量小,那麼就判斷這一位 \(0\) 和 \(1\) 的個數關係即可。
時間複雜度:\(O(nL)\)。
Code:
#include <cstdio> #include <cstring> #include <string> #include <iostream> #include <algorithm> #define MAXN 1001 int n, len, num[MAXN][2]; std::string s; int main() { //freopen("curse.in", "r", stdin); //freopen("curse.out", "w", stdout); std::cin >> n; for (int i = 1; i <= n; ++i) { std::cin >> s; len = s.length(); for (int j = 0; j < len; ++j) { ++num[j][s[j] - '0']; } } for (int i = 0; i < len; ++i) { if (num[i][0] >= num[i][1]) putchar('0'); else putchar('1'); } puts(""); //fclose(stdin), fclose(stdout); return 0; }
T2 神光
由
使得 \(L\) 最小
感覺需要用二分答案。
遇到了怎麼 check
的難題。
不知道怎麼就想到 DP 上了。
設 \(f_{i,j}\) 表示用了 \(i\) 次紅光,\(j\) 次綠光,下一次在使用某一種光的最遠的左端點是哪裡。
虛擬碼:
f[0][0] = 最左邊的法壇
在已知左端點的時候能夠很容易推出下次的左端點。
虛擬碼:
f[i][j] = max(upper_bound(排好序的法壇,f[i - 1][j] + x - 1),upper_bound(排好序的法壇,f[i][j - 1] + 2 * x - 1)
時間複雜度:\(O(n^2log^2n)\)。
Code:
#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>
#define MAXN 2222
int min(int a, int b) { return a < b ? a : b; }
int max(int a, int b) { return a > b ? a : b; }
int n, r, g, a[MAXN];
int f[MAXN][MAXN];
bool check(int x) {
int s1 = min(n, r), s2 = min(n, g);
f[0][0] = a[1];
int stp = min(n, s1 + s2);
for (int k = 1; k <= stp; ++k) {
int stop = min(s1, k);
for (int i = 0; i <= stop; ++i) {
int j = k - i;
if (j > s2) continue;
if (i == 0) {
int pos = std::upper_bound(a + 1, a + n + 1, f[i][j - 1] + 2 * x - 1) - a;
if (pos > n) { f[i][j] = a[n + 1]; return true; }
else f[i][j] = a[pos];
}
else if (j == 0) {
int pos = std::upper_bound(a + 1, a + n + 1, f[i - 1][j] + x - 1) - a;
if (pos > n) { f[i][j] = a[n + 1]; return true; }
else f[i][j] = a[pos];
}
else {
int pos = max(std::upper_bound(a + 1, a + n + 1, f[i][j - 1] + 2 * x - 1) - a, std::upper_bound(a + 1, a + n + 1, f[i - 1][j] + x - 1) - a);
if (pos > n) { f[i][j] = a[n + 1]; return true; }
else f[i][j] = a[pos];
}
}
}
bool okay = false;
for (int i = 0; i <= s1; ++i) {
if (i > stp) break;
if (stp - i > s2) continue;
if (f[i][stp - i] > a[n]) okay = true;
}
return okay;
}
int main() {
scanf("%d %d %d", &n, &r, &g);
for (int i = 1; i <= n ; ++i) scanf("%d", &a[i]);
std::sort(a + 1, a + n + 1);
a[n + 1] = 2147483647;
if (r + g >= n) {
puts("1");
fclose(stdin), fclose(stdout);
return 0;
}
int lft = 1, rght = a[n];
while (lft <= rght) {
int mid = (lft + rght) >> 1;
if (check(mid)) rght = mid - 1;
else lft = mid + 1;
}
std::cout << lft << '\n';
return 0;
}