Submission #622276

#TimeUsernameProblemLanguageResultExecution timeMemory
622276jophyyjhGlobal Warming (CEOI18_glo)C++14
100 / 100
647 ms43072 KiB
/** * Notes during contest. * * ------ A ------ * Looks like a dp. * * ------ B ------ * I think i've seen sth similar on luogu. First, let's assume that d >= 0 and i'll * use the words "increase" & "decrease". If we wanna increase an interval by d, we * can greedily increase a suffix (instead of just an interval in the middle). If we * are to decrease an interval by d, we can greedily decrease a prefix. The two cases * are symmetric, so we can assume that one always increase a suffix by 0 <= d <= x. * And, if we're increasing a suffix, why don't we just do d=x? The rest is quite * straight-forward. * * ------ C ------ * For k_j = 0, we have to find the num of times each interval appeared. This can be * effectively done with str hashing. [S3] solved. [S1] is just brute-force: we can * do a O(n^2) for loop, iterating over all pairs of starting pos, naively comparing * the dist. of 2 substr. [S2] is a O(n^2) comparison between pairs of VALUES and * apply a difference array. * We're only looking for the num of mismatches. Let's compress the values (a_i: * 10^9 -> 10^4). * * Time Complexity 1: O() * Time Complexity 2: O(n * log(n)) * Time Complexity 3: O(n^2 + q) ([S1-2]), O(n) (non-deterministic hashing) * Implementation 1 (Full solution, n * log(n) dp for LIS) */ #include <bits/stdc++.h> typedef int64_t int_t; typedef std::vector<int_t> vec; const int_t INF = 0x3f3f3f3f3f3f3f; int main() { std::ios_base::sync_with_stdio(false); std::cin.tie(NULL); int_t n, x; std::cin >> n >> x; vec values(n); for (int_t k = 0; k < n; k++) std::cin >> values[k]; vec left(n), right(n), min_end(n, INF); for (int_t k = 0; k < n; k++) { int_t t = -1; for (int_t step = n / 2 + 1; step >= 1; step /= 2) { while (t + step < n && values[k] > min_end[t + step]) t += step; } min_end[t + 1] = values[k], left[k] = t + 2; } min_end.assign(n, -INF); for (int_t k = n - 1; k >= 0; k--) { int_t t = -1; for (int_t step = n / 2 + 1; step >= 1; step /= 2) { while (t + step < n && values[k] < min_end[t + step]) t += step; } min_end[t + 1] = values[k], right[k] = t + 2; } vec vals(2 * n); for (int_t k = 0; k < n; k++) vals[2 * k] = values[k], vals[2 * k + 1] = values[k] + x; std::sort(vals.begin(), vals.end()); std::map<int_t, int_t> compress; // compressing index for (int_t k = 0; k < 2 * n; k++) compress[vals[k]] = k; int_t max_len = 0; vec seg_tree(4 * n, -INF); for (int_t k = 0; k < n; k++) { // k: first index of our suffix int_t upper = compress[values[k] + x]; if (k > 0 && upper > 0) { int_t left_len = 0; for (int_t a = 0 + 2 * n, b = upper - 1 + 2 * n; a <= b; a /= 2, b /= 2) { if (a % 2 == 1) left_len = std::max(left_len, seg_tree[a++]); if (b % 2 == 0) left_len = std::max(left_len, seg_tree[b--]); } max_len = std::max(max_len, left_len + right[k]); } for (int_t pt = compress[values[k]] + 2 * n; pt > 0; pt /= 2) seg_tree[pt] = std::max(seg_tree[pt], left[k]); } std::cout << max_len << '\n'; }
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...