AtCoder abc382 参加メモ

AtCoder Beginner Contest 382 - AtCoder

#include <bits/stdc++.h>
using namespace std;
#define REP(i,n) for(int i=0;i<n;i++)
#define endl '\n'

int main() {
  int n,d; string s; cin >> n >> d >> s;
  for(auto c: s) if (c == '@') n--;
  cout << n+d << endl;
  return 0;
}
#include <bits/stdc++.h>
using namespace std;
#define REP(i,n) for(int i=0;i<n;i++)
#define endl '\n'

int main() {
  int n,d; string s; cin >> n >> d >> s;
  for(int i = n-1; i >= 0; i--) if (d && s[i] == '@') s[i] = '.', d--;
  cout << s << endl;
  return 0;
}

C - Kaiten Sushi

寿司はどの順番で流しても結果に変わりはない。

寿司の美味しさの降順に処理することにすれば、美味しさが大きいものは先頭から取っていくので、a[cur] 以降の人だけをチェックしていくだけで良くなる。

#include <bits/stdc++.h>
using namespace std;
#define REP(i,n) for(int i=0;i<n;i++)
#define endl '\n'
using P = pair<int,int>;

int main() {
  int n,m; cin >> n >> m;
  vector<int> a(n),b(m);
  REP(i,n) cin >> a[i];
  REP(i,m) cin >> b[i];
  vector<P> pb;
  REP(i,m) pb.emplace_back(b[i],i);
  sort(pb.rbegin(),pb.rend());

  vector<int> ans(m,-1);
  int cur = 0;
  REP(i,m) {
    while(cur < n) {
      if (a[cur] <= pb[i].first) {
        ans[pb[i].second] = cur+1;
        break;
      }
      cur++;
    }
  }
  for(auto v: ans) cout << v << endl;
  return 0;
}

D - Keep Distance

DFS がうまく書けますかという問題。DFS の計算量怪しいなと思いつつも i <= m で投げて TLE を出してしまった。 達成不可能な数列をちゃんと枝刈りすれば間に合った。

#include <bits/stdc++.h>
using namespace std;
#define REP(i,n) for(int i=0;i<n;i++)
#define endl '\n'

int main() {
  int n,m; cin >> n >> m;
  vector<int> a;
  vector<vector<int>> ans;

  auto dfs = [&](auto dfs) -> void {
    int sz = a.size();
    if (sz == n) { ans.push_back(a); return; }

    for(int i = sz ? a.back()+10 : 1; i <= m-(10*(n-1-sz)); i++) {
      a.push_back(i);
      dfs(dfs);
      a.pop_back();
    }
  };

  dfs(dfs);
  cout << ans.size() << endl;
  for(auto v: ans) {
    for(auto w: v) cout << w << " ";
    cout << endl;
  }
  return 0;
}

E - Expansion Packs

期待値問題。難しい。

#include <bits/stdc++.h>
using namespace std;
#define REP(i,n) for(int i=0;i<n;i++)
#define endl '\n'

int main() {
  int n,x; cin >> n >> x;
  vector<double> p(n);
  REP(i,n) cin >> p[i], p[i] /= 100.0;

  // dp[i][j] := パック内の i 枚目まででレアカードを j 枚持つ確率
  vector<double> dp(n+1);
  dp[0] = 1.0; // レアカード 0 枚は 100 %
  REP(i,n) {
    vector<double> prev(n+1);
    swap(dp,prev);
    REP(j,i+1) {
      dp[j] += prev[j] * (1.0 - p[i]); // レアカードが出ない
      dp[j+1] += prev[j] * p[i]; // レアカードが出る
    }
  }

  // f[i] := レアカードが x 枚になるまで必要なパック数の期待値
  vector<double> f(x+1);
  for(int i = 1; i <= x; i++) {
    double sum = 0.0;
    for(int j = 1; j <= min(i-1,n); j++) sum += dp[j] * f[i-j];
    sum += 1.0;
    // f[i] = dp[0] * f[i] + sum
    // f[i] = sum / (1 - dp[0])
    f[i] = sum / (1.0 - dp[0]);
  }

  printf("%.10f\n", f[x]);
  return 0;
}

F - Falling Bars

hの大きい(下にある)バーから順に処理。 遅延セグ木で range min を求めることで、バーをどこまで移動できるかを管理する

#include <bits/stdc++.h>
#include <atcoder/all>
using namespace atcoder;
using namespace std;
#define REP(i,n) for(int i=0;i<n;i++)
#define endl '\n'
using T = tuple<int,int,int>;
const int INF = numeric_limits<int>::max();

using S = int;
using F = int;
S op(S a, S b) { return min(a,b); }
S e() { return INF; }
S mapping(F f, S x) { return min(x,f); }
F composition(F f, F g) { return min(f,g); }
F id() { return INF; }

int main() {
  int h,w,n; cin >> h >> w >> n;
  vector bars(h,vector<T>());
  REP(i,n) {
    int r,c,l; cin >> r >> c >> l; r--; c--;
    bars[r].emplace_back(c,l,i);
  }

  lazy_segtree<S, op, e, F, mapping, composition, id> seg(w);
  seg.apply(0,w,h-1);
  vector<int> ans(n);
  for(int r = h-1; r >= 0; r--) {
    for(auto [c,l,id]: bars[r]) {
      int now = seg.prod(c,c+l);
      ans[id] = now;
      seg.apply(c,c+l,now-1);
    }
  }

  REP(i,n) cout << ans[i]+1 << endl;
  return 0;
}

雑感

hightest 更新!順位も過去最高だった。G は手も足も出ず。

tic40さんのAtCoder プログラミングコンテスト2024(AtCoder Beginner Contest 382)での成績:325位
パフォーマンス:1911相当
レーティング:1233→1322 (+89) :)
Highestを更新しました!
#AtCoder #AtCoderプログラミングコンテスト2024(ABC382) https://atcoder.jp/users/tic40/history/share/abc382?lang=ja