京都大学プログラミングコンテスト2015 H - Bit Count
で0である桁について, を1にしたとしても と のビットカウントが1ずつ増加するだけである. が増えて損するだけなので, で1にする桁は も1の桁だけである.
下の桁から順に を0にするか1にするかを決定していくdpを行う. のうち を0/1のどちらにするか決まっていない部分を , に対して を決めるとビットカウントが であるときの の最小 とする.
- (が偶数 の一番下の桁が0)
を0にするのでビットカウントの差は から変化しない.残りのの部分でビットカウントの差が になる最小の を求め,2倍することで で桁を一つ落とした分のつじつまを合わせる. -
- を1にする場合
繰り上がるので残りの の部分に1を足す.ビットカウントの差はこの操作で-1されるのでになる.偶数の場合と同様2倍し,の一番下の桁を1にするので1を足す. - を0にする場合
残りの の部分は を1ビット右シフト となる.ビットカウントの差は+1されるのでになる.偶数の場合と同様2倍する.
- を1にする場合
このDPを全ての について行うのは不可能である.DPの遷移に注目すると を2で割る操作ばかりであり, の付近の数しか実は関わらない.よって が取りうる値の個数は 個しかないため,メモ化再帰等を用いることで答えを求められる.
#include <bits/stdc++.h> using namespace std; using ll = long long; using PII = pair<ll, ll>; #define FOR(i, a, n) for (ll i = (ll)a; i < (ll)n; ++i) #define REP(i, n) FOR(i, 0, n) #define ALL(x) x.begin(), x.end() template<typename T> void chmin(T &a, const T &b) { a = min(a, b); } template<typename T> void chmax(T &a, const T &b) { a = max(a, b); } struct FastIO {FastIO() { cin.tie(0); ios::sync_with_stdio(0); }}fastiofastio; #ifdef DEBUG_ #include "../program_contest_library/memo/dump.hpp" #else #define dump(...) #endif const ll INF = 1LL<<60; map<PII,ll> memo; ll dfs(ll n, ll diff) { if(n == 0) { if(diff == 0) return 0; return INF; } if(n == 1) { if(diff == 0) return 1; if(diff == 1) return 0; return INF; } if(memo.find(PII(n, diff)) != memo.end()) return memo[PII(n, diff)]; ll ret; if(n%2 == 0) { ret = dfs(n/2, diff) * 2; if(ret >= INF) ret = INF; } else { ret = min(dfs((n+1)/2, diff+1)*2+1, dfs(n/2, diff-1)*2); if(ret >= INF) ret = INF; } return memo[PII(n, diff)] = ret; } int main(void) { ll t; cin >> t; while(t--) { ll n; cin >> n; cout << dfs(n, 0) << endl; } return 0; } ``