Submission #1272492

#TimeUsernameProblemLanguageResultExecution timeMemory
1272492witek_cppLet's Win the Election (JOI22_ho_t3)C++20
100 / 100
1748 ms8388 KiB
#include <bits/stdc++.h> using namespace std; using ld = long double; const ld INF = 1e18L; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int n, k; if (!(cin >> n >> k)) return 0; vector<pair<ld,ld>> elms; elms.reserve(n); for (int i = 0; i < n; ++i) { ld A, B; cin >> A >> B; if (B < 0) B = INF; // brak pomagiera -> bardzo duże B elms.push_back({B, A}); // sortujemy po B, a przechowujemy (B,A) } sort(elms.begin(), elms.end()); // kupujemy pomagierów w rosnącej kolejności B // przepisujemy do 1-based arrays po sortowaniu vector<ld> A(n+1), B(n+1); for (int i = 0; i < n; ++i) { B[i+1] = elms[i].first; A[i+1] = elms[i].second; } // dp_kth_small[i][d] = minimalny czas potrzebny, aby z przedziału [i..n] // zdobyć dokładnie d głosów, jeśli od razu mamy (ile+1) mówiących (prędkość = ile+1). // dp[i][d] = minimalny czas potrzebny rozważając prefix pierwszych i stanów // żeby kupić dokładnie d pomagierów (i przy tym już "zarezerwować" czas // na pozyskane głosy z prefixu jako A/(ile+1)). vector<vector<ld>> dp_kth_small(n+2, vector<ld>(n+1, INF)); vector<vector<ld>> dp(n+1, vector<ld>(n+1, INF)); ld answer = INF; for (int ile = 0; ile <= n; ++ile) { // przygotuj dp_kth_small dla prędkości (ile+1) for (int d = 0; d <= n; ++d) dp_kth_small[n+1][d] = INF; dp_kth_small[n+1][0] = 0; for (int i = n; i >= 1; --i) { for (int d = 0; d <= n; ++d) { // nie bierz stanu i do głosów z suffixu dp_kth_small[i][d] = dp_kth_small[i+1][d]; // weź ten stan jako jeden z d głosów (koszt A[i]/(ile+1)) if (d > 0) dp_kth_small[i][d] = min(dp_kth_small[i][d], dp_kth_small[i+1][d-1] + A[i] / (ile + 1)); } } // jeżeli nie kupujemy żadnego pomagiera, wynik to po prostu // minimalny czas aby zdobyć k głosów przy prędkości 1 (czyli ile+1 = 1) if (ile == 0) answer = min(answer, dp_kth_small[1][k]); // przygotuj dp dla prefixów for (int i = 0; i <= n; ++i) for (int d = 0; d <= n; ++d) dp[i][d] = INF; dp[0][0] = 0; for (int i = 1; i <= n; ++i) { for (int d = 0; d <= i; ++d) { // opcja: nie kupujemy tutaj pomagiera -> "odkładamy" ten stan do fazy po kupnie wszystkich pomagierów if (dp[i-1][d] < INF) dp[i][d] = min(dp[i][d], dp[i-1][d] + A[i] / (ile + 1)); // opcja: kupujemy tutaj pomagiera (d>=1). Przed zakupem mieliśmy (d-1) pomagierów, // czyli aktualna liczba mówiących to (d-1)+1 = d, więc koszt B[i]/d if (d >= 1 && dp[i-1][d-1] < INF) dp[i][d] = min(dp[i][d], dp[i-1][d-1] + B[i] / (ld)d); // jeżeli już kupiliśmy dokładnie 'ile' pomagierów w prefixie długości i, // to możemy połączyć czas wydany na kupno z czasem potrzebnym, żeby z suffixu [i+1..n] // zdobyć brakujące głosy. Tutaj używamy dokładnie tego samego mechanizmu // co w Twoim oryginalnym działającym kodzie. if (d == ile) { int need_from_suffix = max(0, k - i); // tak jak w Twoim działającym kodzie if (need_from_suffix <= n) { answer = min(answer, dp[i][d] + dp_kth_small[i+1][need_from_suffix]); } } } } } cout.setf(std::ios::fixed); cout << setprecision(9) << (double)answer << "\n"; 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...