제출 #1295350

#제출 시각아이디문제언어결과실행 시간메모리
1295350blinkyFeast (NOI19_feast)C++20
100 / 100
92 ms10932 KiB
#include <iostream> #include <vector> #include <algorithm> using namespace std; const long long INF = 1e18; const int MAXN = 300005; int n, k; vector<int> a; // Global DP arrays to prevent reallocation overhead (Speed optimization) // storing {score, count} pair<long long, int> dp0[MAXN]; // Gap state pair<long long, int> dp1[MAXN]; // Active state // Returns {max_score, items_picked} for a given penalty lambda pair<long long, int> check(long long lambda) { // Base cases // dp0[0]: In a gap at index 0 (didn't pick a[0]) dp0[0] = {0, 0}; // dp1[0]: Active at index 0 (Must have started a new segment) // Note: We pay the lambda cost immediately upon starting dp1[0] = {a[0] - lambda, 1}; for (int i = 1; i < n; i++) { // --- 1. Calculate DP0 (Gap State) --- // We are NOT eating a[i]. Came from Gap(i-1) or Active(i-1). // If scores are equal, we usually prefer fewer segments to be safe, // but standard max logic works fine here. if (dp0[i-1].first >= dp1[i-1].first) { dp0[i] = dp0[i-1]; } else { dp0[i] = dp1[i-1]; } // --- 2. Calculate DP1 (Active State) --- // We ARE eating a[i]. // Option A: Extend current segment (Free, just add a[i]) long long extend_score = dp1[i-1].first + a[i]; int extend_cnt = dp1[i-1].second; // Option B: Start new segment (Pay Lambda) long long start_new_score = dp0[i-1].first + a[i] - lambda; int start_new_cnt = dp0[i-1].second + 1; if (start_new_score > extend_score) { dp1[i] = {start_new_score, start_new_cnt}; } else { dp1[i] = {extend_score, extend_cnt}; } } // Return the better of the two final states if (dp0[n-1].first > dp1[n-1].first) return dp0[n-1]; return dp1[n-1]; } int main() { // Optimization for faster I/O ios_base::sync_with_stdio(false); cin.tie(NULL); if (!(cin >> n >> k)) return 0; a.resize(n); for (int i = 0; i < n; i++) { cin >> a[i]; } // Binary Search Range // Low must be 0 (At most K logic). // High is roughly max possible sum (3e14), 1e15 is safe. long long low = 0, high = 1e15; long long ans_lambda = 0; while (low <= high) { long long mid = low + (high - low) / 2; pair<long long, int> res = check(mid); // If we pick >= K segments, the penalty is too cheap (or just right). // We want the largest penalty that still gives us >= K segments // (closest to touching the curve at K). if (res.second >= k) { ans_lambda = mid; low = mid + 1; // Try to increase penalty } else { high = mid - 1; } } // Final Reconstruction pair<long long, int> final_res = check(ans_lambda); // If the best lambda (0) still gave us < K segments, it means // it's optimal to pick fewer than K. The rest are empty segments (sum 0). // In that case, the formula adds 0 * K, which is correct. // However, if we forced it with a positive lambda, we add back K * lambda. long long answer = final_res.first + (long long)k * ans_lambda; cout << answer << endl; return 0; }
#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...