ABC235F Variety of Digits
自力AC(一度TLEになったので、解法を見て、合っているか確認した)
- 条件を満たす桁に関する問題
- 以下の整数全てに関する問題
という条件から、桁DPが有力候補となります。
桁DPに関する情報はネット上に多くあるため、ここでは割愛しますが、大雑把に説明します。
桁DPでは上位桁より考慮していきます。
の上から桁目をとし、を以下にしたいとします。
の上から桁目までが、と同じだったとします。すると、の桁目をより大きくすると、はを超えます。よって、の桁目は以下にする必要があります。
次に、桁目までで、既にの桁より小さい桁が存在する(すなわち、は未満となっていることが確定している)とします。
この場合、の桁目は0〜9までなんでも良いです。
以上から、の桁目を決定するときに、桁目までがと同じなのか、もしくは既に未満なのか、という情報が必要になることがわかります。
桁DPでは、これを未満フラグとして管理し、
- 未満フラグが0なら、ここまでの桁がと同一
- 未満フラグが1なら、既に未満であることが確定している
とします。
桁DPについては以上です。
最悪となる全状態数と遷移にかかる時間を見積ります。
の各桁に対応して、以下の2つを管理する必要があります。
- 0〜9のどの整数が出現したか
- 未満フラグ
1については、冪集合で管理するので、通りあります。
従って、状態数の最悪は
となります。
最悪計算量については、桁目の全状態に対して、桁目に0〜9を付加することを考えると、状態数の10倍の時間がかかるので、 くらいとなって、なんとか大丈夫です。
実際のDPを考えます。
上から番目の桁までを考えたきに、未満フラグがであって、整数の出現状態がであるものの総和
以下の例で遷移を考えてみます。
例えば、N = 99999として、{1,2}が出現していて、上から3桁目を7にするとします(未満フラグを1で確定している状況)。
この場合、7の付け方は上記の2通りが存在します 。
DP遷移で考えてみます。
ここで問題となるのが、和を計算する時に、700が2個発生しています。なぜ2個発生したかというと、2桁目までで{1,2}が出現したもの(すなわち、という状態であるもの)が2個存在していたからです。
このことから、和を計算するときには、同時に状態の個数が必要となります。よって、以下の2つのDPを考えます。
上から番目の桁までを考えたきに、未満フラグがであって、整数の出現状態がであるものの個数
上から番目の桁までを考えたきに、未満フラグがであって、整数の出現状態がであるものの総和
遷移式は、の桁数を、桁目をとし、桁目をにしたとすると、
となります。但し、はビット毎のOR演算で、は左ビットシフト演算です。
初期値は、で、あとは全て0です。
左辺の詳細はネット上にもありますが、というのは、遷移後に未満フラグが1となるのは、すでに未満フラグが1の時か、または、考慮する桁の数がの桁目未満だった時であるため、このような表現になります(trueを1、falseを0としています)。
なお、このまま実装するとダメな部分があります。
- leading 0を省く処理
実装上、0のみ出現している状態({0,0,0,0,0,0,0,0,0,0,1})が常に1つあることにしておいた方が楽です。しかし、そのままだと0が既に出現していると誤判定してしまいます。そこで、0しか出現していない状態から遷移するときには0が出現していないことにする処理を加えて対処しました。
例
にする。
出現状態は普通にすると
という遷移になってしまうので、0bit目を0にする。
- 10の冪乗部分の処理
を毎回繰り返し二乗法で計算していたら、TLEしました。
そのため、前計算しておき、配列などに保持しておく必要がありました。
答えは、のビットが全て1である集合を部分集合にもつ集合について、の総和です(詳細は実装をご覧ください)。