競技プログラミング日記

主に AtCoder の記事です

AtCoder Beginner Contest 192F

ABC192F

簡単な問題から考える.

取り方 \(s \in 2^{N}\) を固定

\(t := sum(s)\) とおく. \(s\) に対する答えは, \(x-t \equiv 0 \ mod \ |s|\) のとき \(\frac{x-t}{|s|}\) となる. それ以外のときは不可能.

取った個数 \(k \in [1,N]\) を固定

これも同様. \(k = |s|\) となる \(s \in 2^{N}\) を考える. \(\frac{x-t}{k}\) を最小にしたいから, 和 \(t\) を最大にすればよい.
答えは \(max_{s \in 2^{N} \\ |s| = k \\ x-t \equiv 0 \ mod \ k} \frac{x-t}{k}. \)

本問

取った個数 \(k\) を全探索する.
\(dp^{k}_{i,j,r} := \) \(max_{s \in 2^{i} \\ |s| = j \\ t \equiv r \ mod \ k} sum(s) \).
ans = \(min_{k \in [1,N] \\ dp^{k}_{N,k,x} \geq 0 \\ dp^{k}_{N,k,x} \equiv 0 \ mod \ k} \frac{x- dp^{k}_{N,k,x}}{k}\)

使っている記号,マクロ等 "https://ecsmtlir.hatenablog.com/entry/2022/12/23/131925"

int main() {
  ll n,x;
  cin >> n >> x;
  vll a(n); rep(i,n) { cin >> a[i]; }

  ll ans = INFL;
  rep1(k,n) {
    vvll dp(k+1, vll(k, -INFL));
    dp[0][0] = 0;
   
    rep(i,n) {
      drep(j,k){ // 使った個数
        rep(r,k){
          chmax(dp[j+1][(r+a[i])%k], dp[j][r] + a[i]);
        }
      }
    }

    ll s = dp[k][x%k];
    if(s >= 0){
      assert((x-s) % k == 0);
      chmin(ans, (x - s) / k);
    }
  }

  cout << ans << endl;

  return 0;
}