ARC037 C-億マス計算
【問題】
【方針】
K 番目に小さい値を求める問題 (CodeForces 191E) を最近やっていて、それと同じく二分探索でやるのかなと最初に思う。ちょっと考えたら、ある値 S より小さいようなマス目の値は std::set で簡単に求まりそうなので、実装する。難なく AC と思ったものの、なぜか 2 つのケースで落ちて通らない。コードを見直してみたけれど、致命的な欠点は見つからない。そこで同じようなミスをしてる人のコードを submission からいくつか見てみて、二分探索での upper_bound の値を 1e18+1 (1≦a,b≦10^9 なので、マス目の値がこれ以上になることはないはず) から 1e19 にしたところ AC。Twitter で聞いたところによると、e による指数演算は内部で数を double 型で持っていて、精度が高々 16 桁程度しか保証されていないらしい (いわゆる情報落ち誤差で +1 が無視されてた)。で、数をそのまま愚直にリテラルで書くか、1e18L+1 みたいに long double 型に変換してから加算すればちゃんと動く。C++ 使って 1 年くらいになるけど、全く知らなかった。
【コード】
- int main() {
- ios::sync_with_stdio(false);
- ll n,k;
- cin>>n>>k;
- vector<ll> a(n);
- vector<ll> b(n);
- REP(i,n) cin>>a[i];
- REP(i,n) cin>>b[i];
- sort(ALL(a));
- sort(ALL(b));
- ll lb=1,ub=1e18L+1;
- while(ub-lb>1) {
- ll mid=(lb+ub)/2;
- ll cnt=0;
- REP(i,n) {
- ll thr=(mid-1)/a[i];
- auto ite=upper_bound(ALL(b),thr);
- cnt+=n-(int)(b.end()-ite);
- }
- if(cnt<k) lb=mid;
- else ub=mid;
- }
- cout<<lb<<endl;
- }
【使ったアイデア】
K 番目に小さい値を二分探索で見つける (自分より小さい値が K 個未満しかないような最大の値が、K番目に小さい値)。
【得た知見】
e を使って指数演算をするときは型に気をつける。