CF 798 D - Mike and distribution
問題
問題概要
長さの数列とが与えられる。
いま、数列のindexを個選ぶことが出来る。選んだ個のindexをとするとき、次の条件を満たすように個のindexを選べ:
このような条件を満たすを答えよ。
アイデア
まず、は多いほうが得だから限界まで増やすことにする。
そして、このとのペアを、残っている中で、aが最大
→bが最小
→aが最大
→…と交互にルールを適用していって並べていく。例を示すと、の時は次のようになる。
このように並べることで、局所的に大小関係が発生するので、奇数番目に現れるものを選んでいけば必ず全体の和の半分より大きい値を得られる。が偶数の時は、最後のindexを1つ前に詰めておけばよい。
乱択でも通ってしまうっぽい…(submission)。
実装(C++)
続きを読むCF 785 D - Anton and School - 2
問題
問題概要
(
と)
のみで構成される文字列について、次のような長さの文字列をregular simple bracket sequences(RSBS)
と呼ぶことにする:
- 空文字列ではない()
- は偶数で、前半の文字は全て
(
、後半の文字は全て)
例えば((()))
はRSBSで、())
や(()())
はRSBSではない。
今、(
と)
のみで構成される文字列が与えられる。からいくつかの文字を削除してRSBSを作成したいと思う時、その方法は何通りあるか、で割った余りを答えよ。
アイデア
要するに、の部分文字列の中でRSBSの個数を求めたい。まず、自分で考えたこととしてはを先頭から走査していってその時点で左にある(
の合計(個とする)と右にある)
の合計(個とする)がわかっていれば、現在注目している箇所の(
を必ず採用すると仮定してで組み合わせの総数を列挙できるなーとは思った。けれど、それを全ての(
に対してやるのは間に合わない。
実は、1箇所の(
に注目して、それより左にある(
の個数が個でそれより右にある)
の個数が個の時のRSBSの構成方法の場合の数はもっと簡単に計算できる。
シンプルな場合として、前半文字が(
で後半文字が)
のような文字列からRSBSを構成することを考えると、この場合は通りになる。なぜこうなるかを、個の1と個0を並べる順列に対応付けて考える。
以下に例を示す:
s: ((()))) select: ( ( )) convert: 0100110
元の文字列がであるときに、このように部分文字列を構成すると、01はこのように対応させる。これは具体的に何をやっているかというと、部分文字列として採用された(
に0、されない(
に1、採用された)
に1、されない)
に0を付与している。この方法によって、0は個、1は個になる。
採用された(
が個とすると、採用された)
も個。つまり採用されない)
は個。ということで、0は合計で個になる。前から順番に括弧を対応させていくことで一対一にこの文字列が定まるというわけである。
実際に走査していく時は、一番右にある(
は必ず採用する仮定があるので、01の対応で言うと0が1つ減ることになる。よって、通りになる。
あとは、はじめに)
の数を数えておいて、操作しながら減らしていき、combinationを計算すれば良い。combinationは階乗を事前に計算して、繰り返し二乗法を利用すれば逆元も計算できる。