公式
M - 点の距離/Distance on the Line 解説
by
M - 点の距離/Distance on the Line 解説
by
Nyaan
この問題は次のような問題として考えることができます。
- はじめ変数 \(x=0\) がある。\(i=1,\dots,N\) について \(x\) に \(A_i\) か \(-A_i\) のいずれか一方を足す。最終的に得られる \(x\) のうち \(\mathrm{abs}(x)\) の最小値は?
上記のように言い換えると、この問題は部分和問題と等価な問題で、動的計画法 (DP) を利用して \(\mathrm{O}(N^2 \max(A))\) で計算できると分かります。
このままでは実行時間制限に間に合いませんが、DP で持つ値が true/false の 2 値なので DP の値を 64 個置きに区切って 64 bit 整数に格納していくことで DP の 64 個の遷移を 1 回でまとめて行う定数倍高速化が可能で、計算量は \(w=64\) として \(\mathrm{O}(N^2 \max(A) / w)\) に高速化できて実行時間制限に十分間に合います。実装は C++ を利用すれば std::bitset
等を利用することで容易に実装できます。
- 実装例 (C++)
#include <bitset>
#include <iostream>
#include <map>
#include <vector>
using namespace std;
bitset<4006400> bs;
int solve(int, vector<int> D) {
bs.reset();
int offset = 2002002;
bs[offset] = 1;
for (auto& d : D) bs = (bs << d) | (bs >> d);
int ans = 1 << 30;
for (int i = 0; i < (int)bs.size(); i++) {
if (bs.test(i)) ans = min(ans, abs(i - offset));
}
return ans;
}
int main() {
int N;
cin >> N;
vector<int> D(N - 1);
for (auto& d : D) cin >> d;
cout << solve(N, D) << "\n";
}
投稿日時:
最終更新: