Submission #1139636

#TimeUsernameProblemLanguageResultExecution timeMemory
1139636vuavisaoHomecoming (BOI18_homecoming)C++20
100 / 100
141 ms78724 KiB
#include <bits/stdc++.h> #pragma GCC optimize("O3", "unroll-loops") using namespace std; template<typename Lhs, typename Rhs> bool Min_self(Lhs& lhs, Rhs rhs) { if(rhs < lhs) { lhs = rhs; return true; } return false; } template<typename Lhs, typename Rhs> bool Max_self(Lhs& lhs, Rhs rhs) { if(rhs > lhs) { lhs = rhs; return true; } return false; } using ll = long long; const ll INF = 1'000'000'000'000'000'000; ll brute_force(int n, int k, int *a, int *b) { vector<ll> profit(n + 1); vector<ll> cost(2 * n + 1); for (ll i = 1; i <= n; ++i) { profit[i] = a[i - 1]; } auto get_cost = [&] (ll pos) -> ll { return cost[pos + k - 1] - cost[pos - 1]; }; vector<ll> dp(n + 1, -INF); auto get_cost_bonus = [&] (ll pos) -> ll { return dp[pos] + cost[pos + k - 1]; }; ll res = 0; for (ll first = 1; first <= k; ++first) { fill(dp.begin(), dp.end(), -INF); auto get_intersect = [&] (ll pos) -> ll { ll right_pos = pos + k - 1; if (right_pos <= n) return 0; right_pos -= n; ll right_first = first + k - 1; if (first <= right_pos && right_pos <= right_first) { return cost[right_pos] - cost[first - 1]; } return 0; }; for (ll i = 1; i <= n; ++i) { cost[i] = cost[i + n] = b[i - 1]; } for (ll i = 1; i <= 2 * n; ++i) { cost[i] += cost[i - 1]; } dp[first] = profit[first] - get_cost(first); for (ll i = 1; i <= n; ++i) { cost[i] = cost[i + n] = b[i - 1]; if (first <= i && i <= first + k - 1) { cost[i] = cost[i + n] = 0; } } for (ll i = 1; i <= 2 * n; ++i) { cost[i] += cost[i - 1]; } deque<ll> dq; dq.push_back(first); ll max_no_bonus = -INF; for (ll i = first + 1; i <= n; ++i) { while (!dq.empty() && dq.front() <= i - k) dq.pop_front(); ll bonus = get_intersect(i); if (i - k >= first) { Max_self(max_no_bonus, dp[i - k]); } Max_self(dp[i], max_no_bonus - get_cost(i) + bonus); if (!dq.empty()) { Max_self(dp[i], get_cost_bonus(dq.front()) - cost[i + k - 1] + bonus); } dp[i] += profit[i]; while (!dq.empty() && get_cost_bonus(dq.back()) <= get_cost_bonus(i)) { dq.pop_back(); } dq.push_back(i); } Max_self(res, *max_element(dp.begin(), dp.end())); } for (ll i = 1; i <= n; ++i) { cost[i] = cost[i + n] = b[i - 1]; } for (ll i = 1; i <= 2 * n; ++i) { cost[i] += cost[i - 1]; } fill(dp.begin(), dp.end(), -INF); ll max_no_bonus = -INF; deque<ll> dq; for (ll i = 1; i <= n; ++i) { while (!dq.empty() && dq.front() <= i - k) dq.pop_front(); dp[i] = -get_cost(i); if (i > k) { Max_self(max_no_bonus, dp[i - k]); } Max_self(dp[i], max_no_bonus - get_cost(i)); if (!dq.empty()) { Max_self(dp[i], get_cost_bonus(dq.front()) - cost[i + k - 1]); } dp[i] += profit[i]; while (!dq.empty() && get_cost_bonus(dq.back()) <= get_cost_bonus(i)) { dq.pop_back(); } dq.push_back(i); } Max_self(res, *max_element(dp.begin(), dp.end())); return res; } ll solution(int n, int k, int *a, int *b) { ll res = 0; if (k == n) { Max_self(res, accumulate(a, a + n, 0ll) - accumulate(b, b + n, 0ll)); return res; } // Nhận xét 1: // Nếu ta sử dụng i, j mà i + k <= j // thì rõ ràng từ i + 1 -> j - 1 đều nên được chọn hết // Nhận xét 2: // Nếu coi như không có giao điểm ngược mọi i + k - 1 > n đều phải mua // thì dp như thường // còn nếu đã có giao điểm ngược, tức chi phí bị giảm đi thay vì bị tính 2 lần // thì rõ ràng điểm đầu mút trái sẽ là trong khoảng [n - k + 2, n] // còn đầu mút phải sẽ là trong khoảng [1, k - 1] // Do đó theo nhận xét 1 thì mọi điểm ở giữa đều nên được mua // Hay nếu nó là lời giải tốt nhất thì kiểu gì 1 cũng được chọn // Mà khi 1 đã được chọn thì chỉ cần mua 1 điểm trong [n - k + 2, n] thì mọi điểm sau -> n sẽ free hết // Do đó ta chỉ cần dp chọn 1 và không chọn 1 (không chọn 1 thì tính như cost không có giao) // Còn chọn 1 thì từ điểm được chọn [n - k + 2, n] + 1 -> n đều được free hết // sử dụng lại brute nhưng first <= 1 vector<ll> profit(n + 1); vector<ll> cost(2 * n + 1); for (ll i = 1; i <= n; ++i) { profit[i] = a[i - 1]; } auto get_cost = [&] (ll pos) -> ll { return cost[pos + k - 1] - cost[pos - 1]; }; vector<ll> dp(n + 1, -INF); auto get_cost_bonus = [&] (ll pos) -> ll { return dp[pos] + cost[pos + k - 1]; }; for (ll first = 1; first <= 1; ++first) { fill(dp.begin(), dp.end(), -INF); auto get_intersect = [&] (ll pos) -> ll { ll right_pos = pos + k - 1; if (right_pos <= n) return 0; right_pos -= n; ll right_first = first + k - 1; if (first <= right_pos && right_pos <= right_first) { return cost[right_pos] - cost[first - 1]; } return 0; }; for (ll i = 1; i <= n; ++i) { cost[i] = cost[i + n] = b[i - 1]; } for (ll i = 1; i <= 2 * n; ++i) { cost[i] += cost[i - 1]; } dp[first] = profit[first] - get_cost(first); for (ll i = 1; i <= n; ++i) { cost[i] = cost[i + n] = b[i - 1]; if (first <= i && i <= first + k - 1) { cost[i] = cost[i + n] = 0; } } for (ll i = 1; i <= 2 * n; ++i) { cost[i] += cost[i - 1]; } deque<ll> dq; dq.push_back(first); ll max_no_bonus = -INF; for (ll i = first + 1; i <= n; ++i) { while (!dq.empty() && dq.front() <= i - k) dq.pop_front(); ll bonus = get_intersect(i); if (i - k >= first) { Max_self(max_no_bonus, dp[i - k]); } Max_self(dp[i], max_no_bonus - get_cost(i) + bonus); if (!dq.empty()) { Max_self(dp[i], get_cost_bonus(dq.front()) - cost[i + k - 1] + bonus); } dp[i] += profit[i]; while (!dq.empty() && get_cost_bonus(dq.back()) <= get_cost_bonus(i)) { dq.pop_back(); } dq.push_back(i); } Max_self(res, *max_element(dp.begin(), dp.end())); } for (ll i = 1; i <= n; ++i) { cost[i] = cost[i + n] = b[i - 1]; } for (ll i = 1; i <= 2 * n; ++i) { cost[i] += cost[i - 1]; } fill(dp.begin(), dp.end(), -INF); ll max_no_bonus = -INF; deque<ll> dq; for (ll i = 1; i <= n; ++i) { while (!dq.empty() && dq.front() <= i - k) dq.pop_front(); dp[i] = -get_cost(i); if (i > k) { Max_self(max_no_bonus, dp[i - k]); } Max_self(dp[i], max_no_bonus - get_cost(i)); if (!dq.empty()) { Max_self(dp[i], get_cost_bonus(dq.front()) - cost[i + k - 1]); } dp[i] += profit[i]; while (!dq.empty() && get_cost_bonus(dq.back()) <= get_cost_bonus(i)) { dq.pop_back(); } dq.push_back(i); } Max_self(res, *max_element(dp.begin(), dp.end())); return res; } long long solve(int n, int k, int *a, int *b) { // return brute_force(n, k, a, b); return solution(n, k, a, b); } #ifdef LOCAL int main() { int T; assert(scanf("%d", &T) == 1); for(int t = 0; t < T; t++) { int N, K; assert(scanf("%d%d", &N, &K) == 2); int *A = new int[N]; int *B = new int[N]; for(int i = 0; i < N; i++) assert(scanf("%d", &A[i]) == 1); for(int i = 0; i < N; i++) assert(scanf("%d", &B[i]) == 1); printf("%lld\n", solve(N, K, A, B)); delete[] A; delete[] B; } return 0; } #endif
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...