#include "festival.h"
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define all(c) ((c).begin()), ((c).end())
#define sz(x) ((int)(x).size())
#ifdef LOCAL
#include <print.h>
#else
#define trace(...)
#define endl "\n" // remove in interactive
#endif
std::vector<int> max_coupons(int AA, std::vector<int> PP, std::vector<int> TT) {
  ll A = AA;
  int n = sz(PP);
  vector<ll> P(n), T(n);
  for(int i = 0; i < n; i++){
      P[i] = PP[i];
      T[i] = TT[i];
  }
  
  vector<int> perm(n);
  iota(all(perm), 0);
  sort(all(perm), [&](int i, int j) {
      if(T[i] == T[j]) return P[i] < P[j];
      return P[i] * T[i] * T[j] + P[j] * T[j] < P[j] * T[i] * T[j] + P[i] * T[i];
      // equivalent to: P[i] * T[i]/(T[i] - 1) < P[j] * T[j]/(T[j] - 1) => valid comparator
  });
  int I = 0; while(I < n && T[perm[I]] > 1) I++;
  // trace(I);
  vector<ll> X_min(I + 1, LLONG_MAX);
  vector<ll> suff(n + 1);
  for(int i = n - 1; i >= 0; i--) suff[i] = suff[i + 1] + P[perm[i]];
  // trace(perm);
  for(int i = I - 1; i >= 0; i--){
      ll p = P[perm[i]];
      ll t = T[perm[i]];
      // (X - p) * t >= X
      // X >= p * t / (t - 1)
      X_min[i] = min(X_min[i + 1], (p * t + t - 2) / (t - 1));
  }
  const int MX = 100; // No more than 3 * 32 reductions!
  int J = 0;
  vector<int> ans;
  while(J < I){
      if(A >= suff[0]){
          ans.clear();
          for(int i = 0; i < n; i++) ans.push_back(perm[i]);
          return ans;
      }
      ll p = P[perm[J]];
      ll t = T[perm[J]];
      if(A >= X_min[J]){
          if( (A - p) * t >= A){
              ans.push_back(perm[J]);
              A = (A - p) * t;
          }
          J++;
      } else break;
  }
  vector<vector<ll>> dp(n + 1, vector<ll>(MX + 1, -1));
  dp[J][0] = A;
  for(int i = J; i < I; i++){
      for(int j = 0; j <= MX; j++){
          if(dp[i][j] == -1) continue;
          ll p = P[perm[i]];
          ll t = T[perm[i]];
          dp[i + 1][j] = max(dp[i + 1][j], dp[i][j]); // skip
          if(j < MX && dp[i][j] >= p){
              ll X = (dp[i][j] - p) * t;
              dp[i + 1][j + 1] = max(dp[i + 1][j + 1], X);
          }
      }
  }
  int best = 0, best_j = 0;
  for(int j = 0; j <= MX; j++){
      ll R = dp[I][j];
      if(R < 0)  continue;
      // [I, I + 1, .., j-1] => suff[I] - suff[j] <= R
      int lo = I, hi = n;
      while(lo < hi){
          int mid = (lo + hi + 1) / 2;
          if(suff[I] - suff[mid] <= R) lo = mid;
          else hi = mid - 1;
      }
      if(lo - I + j > best){
          best = lo - I + j;
          best_j = j;
      }
  }
  int osz = sz(ans);
  int j = best_j;
  for(int i = I; i > J; i--){
      if(dp[i][j] == dp[i - 1][j]) continue; // skip
      ans.push_back(perm[i - 1]);
      j--;
  }
  reverse(ans.begin() + osz, ans.end());
  for(int i = I + best - best_j - 1; i >= I; i--) ans.push_back(perm[i]);
  // reverse(all(ans));
  // trace(ans);
  return ans;
}
| # | Verdict | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict | Execution time | Memory | Grader output | 
|---|
| Fetching results... |