競プロ:小テクニック

問題を解いて得た知見

近く整理したい

最近見たものほど上にある

  • MSTにある辺を使うかもしれないかどうかは、MSTを作ってパスの重みのminと一致するか見る
  • 期待値はまず分解できないか考える
  • 平面グラフのオイラーの定理 $v-e+f=2$
  • 貪欲で最適解が求まるとき、左から貪欲と右から貪欲をすると間はすべてできる
  • 小さいケースで実験する(n=2で表をつくるか、適当なnで実験コードを書く→仮説を立てる)
    • 1~2次元で、法則に従ってグリッドを動く問題などは実験が有用、コーナーケースを網羅しやすい
  • 約数をvectorに入れるやつは$M=10^6$ですら危ない
  • ナップサックの半分全列挙→マージソートで余計なlogがつかない
  • ゲームdp
    • 基本は逆から求めていく
    • 手番によって目的が違うことに注意
  • bitwise xor/or/and の問題はbitごとに独立に考えた方が見通しがいい
  • 括弧列の問題→二値化 or stack
  • 制約が$n \le 10^9$のときintを使わない
  • 偶奇に注目すると漸化式っぽくできることがある
  • 絶対値は場合分けやソートで外す
    • 偶奇に着目することでできる可能性がある
  • nのk進法の桁和がk-1の倍数⇒nはk-1の倍数
  • 奇閉路が存在しない⇔二部グラフ
  • 二部グラフ判定は頂点を倍にしたUnion-Findでできる
    • (a, b)に辺がある→(a, b+n), (a+n, b)をuniteする
    • aとa+nが同じ集合にあれば二部グラフではない
  • 最短路を求めるときに、コストの上限が小さければstackでlogが消える
    • ARC 061 E(辺の引き方を工夫する必要がある)
  • ある配列から要素1つを除いてできるかどうかを判定→左からと右からの2つでそれぞれiまで使ったとき~のdpをする
  • 逆操作を考える
  • ゲーム問題
  • すべてが0の状態から逆算する
  • →偶奇性、xorなど
  • 真似戦略、点対称の位置に置く
  • 相手に負けの状態を押しつける
  • N=0, 1を確かめる(コーナーケース)(N=0は特にcodeforcesで頻出のコーナー)
  • 文字列の辞書順最小→suffixから順にdp
  • マンハッタン距離: $(x, y) \mapsto (x+y, x-y)$と変換
  • 配列に変更を加えて探索するとき、配列のコピーを避けるためには配列を変更→dfs→配列を戻す
  • scanfでchar*を読む → scanf(“ %c”, &a) などと空白を開ける
  • 連結成分→union-find
  • 頂点を2つに分類→最小カット?(燃やす埋める)
  • 1個決めると全部が決まる
  • max{A} -min{A}の最大化(最小化)→maxとminのどちらかを固定する
  • 境界について判定する
  • 損失と利益の両方がある場合、利益を全部取ったことにして、損失の方に利益を加える
    • 燃やす埋める問題
  • 損失と利益を同時に考えることは(一般的には)難しい
  • long long でビットシフト →(1LL « x)
  • 順列の置換はいくつかのサイクルのまとまりとなる
  • 新しい数列を作って中央値を求めるという問題
  • 直接は求められないが、中央値が$X$以上(以下)であるか判定する判定問題が解けるならば、二分探索で境界を探すことが出来て、その境界は最大(最小)値
  • 判定問題の解き方は、$X$以上の個数と$X$未満の個数を求め、比較する
  • 最大値の最小化→二分探索
  • 並列二分探索
    • 普通に考えるとクエリごとに操作をしなければいけなく、$O(NQ)​$とかになる時に使う
    • クエリを先読みし、範囲を記録しておき、中間について順に判定をする二分探索をして$O((Q+N)logN)$
  • 制約が狭いほうから決めていく
  • leading-zeroの桁dp
  • dpテーブルは-1で初期化(遷移できないのかどうか確かめるため)
  • 0初期化するのは、$dp[0][0]$だけ。(0であると確定しているため)
  • 互いに素の数え上げ→包除原理が使える
  • ある頂点から$X$回操作をした結果を大量に求める→ダブリング($2^0, 2^1, 2^2, \dots, 2^k$回操作をした結果は簡単に求まるので、2べきに分解して考える)
  • 一筆書き(準オイラー路)では、端点だけが奇数次数で、端点以外は偶数次数
  • 複雑な経路を単純な経路の組み合わせに分割する
  • 1次式の累積和(1, 2, 3, 4, 5 …を範囲に加算するなど)をするには、ax+bで配列を2本持つと見通しがいい
    • これだとオーバーフローする場合があるので注意が必要
  • マンハッタン距離なら、縦横独立して考えられる
  • 不変量に注目する
  • 最大長方形→縦方向に「上に白が何個連なっているか」を見て、横1列ずつに、ヒストグラムの最大長方形の考え方を適用する(蟻本テク)
  • $X$の倍数→$0\mod X$
  • 最下位ビットを取り出す→x&-x
  • 重さがX以下なら重さにYを加算する→X+Yでソート
  • 最小カットにできる→削除するものは辺
  • 貪欲→任意選択
  • $x^p \equiv x \ \ (mod \ p)$(フェルマーの小定理の変形)
  • 境界を全探索
  • 区間を二分探索→ダブリングが便利
  • setを使うとならしでlog
  • gcdは階差を取っても累積和をとっても不変
  • $\min(|x+y|,|x-y|)$,$\max(|x+y|,|x-y|)$は、xとyの符号を変えても不変
  • 最初の要素だけに注目してみる
  • 区間スケジューリングをクエリで→ダブリングで出来る
  • $n$で割った商を見るときは、 $\lfloor \frac{n}{i} \rfloor$が同じグループでまとめる
  • ちょうどK回=(k回以下)-((k-1)回以下)
  • すべての場合のfの総和→fがk以下になる組み合わせを計算
  • $f(a_i) = f(a_j)$ となるように変形すると簡単に数え上げられる
  • 普通のグラフを木にしてみると解ける
  • $4n \oplus 4n+1 \oplus 4n+2 \oplus 4n+3=0$
  • 足し算だけのときの操作回数→逆から見ると引き算になり簡単に求まる
  • 偏角でソートするとうまくいく
  • 二項係数が絡むときは和を$N$までにすると総和を交換しやすくなる
  • 配るDP→形式的冪級数に変換
  • 見る区間が交差していない(完全に含まれるか全く交差しないかのどちらか)のとき、dpをstackでできる。
  • 2点$(x_1, y_1), (x_2, y_2)$を通る直線を管理 → $a = x_2-x_1$と$b = y_2-y_1$→aとbをgcdで割る→$c = x_1*b- y_1*a$として$(a, b, c)$の組で管理
    • 方程式を整理すると$bx-ay = bx_1 - ay_1$になる。
  • コストの上限が小さい→コストの和で計算量が抑えられるかも
  • 基底のマージ
for (auto i : a) {
    for (auto j : b) i = min(i, i^j);
    if(i) b.emplace_back(i);
}
l = 1
while l <= N
    r = N / (N / l) + 1
    // [l, r) は商が等しくなる区間
    l = r
  • 区間の長さ$k$において和が正→区間の長さ$2k$において和が正
  • ゲーム問題では、順番は無視できない
  • 長さ$N$の回文の部分文字列として現れる回文の種類数は高々$N$
  • $X$から$Y$までの$M$の倍数の個数は$\lfloor \frac{Y}{M} \rfloor - \lfloor \frac{X-1}{M} \rfloor$
  • 最終更新: 2021/05/05 05:13
  • by firiexp