TopCoder SRM 443 Div1 Medium
問題
最初A個の0とB個の1が並んでいる。
この中から、異なるちょうどK個の数字を自由に選び、0と1を反転させる操作を行うことができる。
最短でこの操作を何回行えば全ての数字を1にすることが出来るか、求めよ。
操作をどのように行っても1にすることができないとき、-1を返せ。
制約条件
A, B, K≦100000
方針
愚直にBFSするとO( (A + B) * K)時間くらいかかってTLE.
ノードの数は少ないのに、一度訪れたノードへの枝を何回も見てしまうから時間がかかる。
したがって、一度も訪れてないノードをsetに入れて、
一度しか見ないようにしてやる。
すると、O( (A + B) log(A + B) )時間くらいでBFSが出来て通る。
ソースコード
void push(set<int> &s, queue<pi> &q, int lo, int hi, int cost){ set<int>::iterator it = s.lower_bound(lo); set<int> del; for(; it != s.end() && *it <= hi; it++){ q.push(mp(*it, cost)); del.insert(*it); } each(i, del) s.erase(*i); } class BinaryFlips { public: int minimalMoves(int A, int B, int K) { set<int> odd, even; int n = A + B; rep(i, n + 1){ if(i % 2) odd.insert(i); else even.insert(i); } queue<pair<int, int> > q; q.push(mp(A, 0)); while(!q.empty()){ int a = q.front().first, cost = q.front().second; q.pop(); if(a == 0) return cost; int b = n - a; int hi = a + K - 2 * max(0, K - b); int lo = a + K - 2 * min(a, K); if(lo % 2) push(odd, q, lo, hi, cost + 1); else push(even, q, lo, hi, cost + 1); } return -1; } };