#include #include #include #include // Include for std::accumulate, although manual sum is used here // Struct to hold information about a potential discount application // This struct bundles the discount amount with the indices of the item and coupon involved. struct CouponInfo { long long discount; // The amount of discount offered by this coupon on this item int item_idx; // Index of the item (0 to N-1) int coupon_idx; // Index of the coupon (0 to C-1) // Custom comparison operator for sorting CouponInfo objects. // We want to sort in descending order based on the discount amount. // std::sort uses operator< by default. To achieve descending order, // we define `a < b` if `a.discount > b.discount`. bool operator<(const CouponInfo& other) const { // Primary sort key: discount amount (descending order) if (discount != other.discount) { return discount > other.discount; } // Secondary sort keys (optional, used for tie-breaking to ensure deterministic behavior) // If discounts are equal, sort by item index first, then coupon index (ascending). // This tie-breaking doesn't affect the correctness of the final total discount. if (item_idx != other.item_idx) { return item_idx < other.item_idx; } return coupon_idx < other.coupon_idx; } }; int main() { // Use fast I/O operations to speed up input reading. std::ios_base::sync_with_stdio(false); std::cin.tie(NULL); int N; // Number of items int C; // Number of coupons std::cin >> N >> C; // Read item prices. Use long long for prices as they can be large ($10^5$) // and the total price could exceed the range of a 32-bit integer. std::vector P(N); long long total_original_price = 0; for (int i = 0; i < N; ++i) { std::cin >> P[i]; total_original_price += P[i]; // Accumulate the total original price of all items. } // Read coupon details. Each coupon has a type (1 or 2) and a value (X_j). // Store them in a vector of pairs. std::vector> coupons(C); for (int j = 0; j < C; ++j) { std::cin >> coupons[j].first >> coupons[j].second; } // Vector to store all potential discount applications (item-coupon pairs). std::vector potential_discounts; // Pre-allocate memory for the vector if N*C is potentially large. This can improve performance // by avoiding multiple reallocations as elements are added. // Cast N to size_t before multiplying with C to prevent potential integer overflow if N*C // were large enough to exceed maximum int value (though N, C <= 5000 makes this safe anyway). // Check N > 0 and C > 0 because constraints say N, C >= 1. if (N > 0 && C > 0) { // Using try-catch block is good practice for robust code, but often omitted in competitive programming // where constraints usually guarantee valid allocations within limits. try { potential_discounts.reserve(static_cast(N) * C); } catch (const std::bad_alloc& e) { // Optional: error handling for memory allocation failure // std::cerr << "Memory allocation failed: " << e.what() << std::endl; // return 1; // Indicate failure } } // Calculate the discount for every possible pair of item and coupon. for (int i = 0; i < N; ++i) { // Iterate through each item for (int j = 0; j < C; ++j) { // Iterate through each coupon long long current_discount = 0; int type = coupons[j].first; int value = coupons[j].second; if (type == 1) { // Fixed amount discount coupon (T_j = 1) // The discount is the minimum of the item's price P_i and the coupon's fixed value X_j. // The final price is max(P_i - X_j, 0). The discount amount is P_i - max(P_i - X_j, 0) = min(P_i, X_j). // Ensure calculation uses long long to prevent overflow issues. current_discount = std::min(static_cast(value), P[i]); } else { // type == 2, Percentage discount coupon (T_j = 2) // The discount is calculated as P_i * X_j / 100. // The final price is P_i * (100 - X_j) / 100. The discount is P_i - final_price. // Since P[i] is guaranteed to be a multiple of 100, this division results in an exact integer. // Use long long for intermediate multiplication P[i] * value to prevent potential overflow. current_discount = P[i] * static_cast(value) / 100; } // Add the calculated discount info (discount amount, item index, coupon index) // to our list of potential discounts. // Since problem constraints state P_i >= 100 and X_j >= 1, all valid discounts will be positive. potential_discounts.push_back({current_discount, i, j}); } } // Sort the potential discounts. Using the custom comparison operator in CouponInfo struct, // this sorts them in descending order based on the discount amount. std::sort(potential_discounts.begin(), potential_discounts.end()); // Flags to track if an item or a coupon has already been used in the final selection. // Initialize all to false. std::vector item_used(N, false); std::vector coupon_used(C, false); long long total_discount = 0; // Accumulator for the total discount achieved. Initialize to 0. int coupons_applied = 0; // Counter for the number of coupons successfully applied. Initialize to 0. // The maximum number of coupons that can be applied is limited by the number of items (N) // and the number of coupons (C). We can apply at most min(N, C) coupons. int limit = std::min(N, C); // Greedily select the best discounts. // Iterate through the sorted list of potential discounts (from highest discount amount to lowest). for (const auto& info : potential_discounts) { // If we have already applied the maximum possible number of coupons, we can stop early. if (coupons_applied == limit) { break; } int item_idx = info.item_idx; int coupon_idx = info.coupon_idx; // Check if both the item and the coupon involved in this potential discount application // are still available (i.e., have not been used yet). if (!item_used[item_idx] && !coupon_used[coupon_idx]) { // If both are available, we choose to apply this coupon to this item. total_discount += info.discount; // Add the discount amount to the total accumulated discount. item_used[item_idx] = true; // Mark the item as used, so it cannot receive another coupon. coupon_used[coupon_idx] = true; // Mark the coupon as used, so it cannot be applied again. coupons_applied++; // Increment the count of applied coupons. } } // The final minimum cost to buy all items is the total original price minus the maximum total discount achieved. long long final_cost = total_original_price - total_discount; // Output the final minimum cost. Ensure a newline character at the end. std::cout << final_cost << std::endl; return 0; // Indicate successful execution. }