Submission #1254694

#TimeUsernameProblemLanguageResultExecution timeMemory
1254694fasterthanyouFestival (IOI25_festival)C++20
0 / 100
152 ms197444 KiB
#include <bits/stdc++.h> #include <ranges> using namespace std; #ifdef LOCAL #include "../../debug.h" #else #define debug(...) 42 #endif namespace utils { template <typename T> bool chMax(T& target, const T& value) { if (value > target) { target = value; return true; } return false; } template <typename T> bool chMin(T& target, const T& value) { if (value < target) { target = value; return true; } return false; } } // namespace utils using namespace utils; using ll = long long; using ld = long double; using mp = vector<vector<int>>; const char el = '\n'; // Helper function to find the index of the single set bit. // GCC and Clang provide a fast intrinsic for this. int get_bit_index(int n) { #ifdef __GNUC__ return __builtin_ctz(n); // Count Trailing Zeros #else if (n == 0) return 0; int index = 0; while ((n & 1) == 0) { n >>= 1; index++; } return index; #endif } std::vector<int> max_coupons(int A, std::vector<int> P, std::vector<int> T) { int N = P.size(); if (N == 0) { return {}; } int num_masks = 1 << N; // dp[mask] = max tokens after buying coupons in the set 'mask' std::vector<long long> dp(num_masks, -1); // parent[mask] = the mask we came from to optimally reach 'mask' std::vector<int> parent(num_masks, 0); // Base case: 0 coupons bought, we have A tokens dp[0] = A; // Fill the DP table for (int mask = 0; mask < num_masks; ++mask) { // If this state is unreachable, we can't buy more from here if (dp[mask] == -1) { continue; } // Try to buy each coupon 'i' that is NOT in the current mask for (int i = 0; i < N; ++i) { // Check if i-th bit is NOT set in the mask if (!((mask >> i) & 1)) { // Check if we can afford coupon 'i' if (dp[mask] >= P[i]) { long long new_tokens = (dp[mask] - P[i]) * T[i]; int next_mask = mask | (1 << i); // If this path is better, update dp and store the parent if (new_tokens > dp[next_mask]) { dp[next_mask] = new_tokens; parent[next_mask] = mask; } } } } } // Find the best reachable final state (mask) int max_coupons_count = 0; int best_final_mask = 0; long long max_tokens_for_best_path = -1; for (int mask = 0; mask < num_masks; ++mask) { if (dp[mask] != -1) { // Get number of coupons for this mask int current_coupons = __builtin_popcount(mask); // If we found a path with more coupons, it's the new best if (current_coupons > max_coupons_count) { max_coupons_count = current_coupons; best_final_mask = mask; max_tokens_for_best_path = dp[mask]; } // Tie-breaking: if coupon count is the same, prefer more tokens else if (current_coupons == max_coupons_count) { if (dp[mask] > max_tokens_for_best_path) { best_final_mask = mask; max_tokens_for_best_path = dp[mask]; } } } } // If we couldn't afford any coupons if (max_coupons_count == 0) { return {}; } // Reconstruct the path by backtracking from the best final mask std::vector<int> optimal_order; int current_mask = best_final_mask; while (current_mask != 0) { int prev_mask = parent[current_mask]; // The difference in masks gives us the last coupon bought int coupon_mask = current_mask ^ prev_mask; int coupon_index = get_bit_index(coupon_mask); optimal_order.push_back(coupon_index); // Move to the previous state current_mask = prev_mask; } // The path was reconstructed backwards, so reverse it std::reverse(optimal_order.begin(), optimal_order.end()); return optimal_order; }
#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...
#Verdict Execution timeMemoryGrader output
Fetching results...