🍎
【AtCoder】ABC134 B - Golden Apple をいろいろな方法で解いてみた
はじめに
この問題の制約は以下の値でもよさそうです。
1 \le N \le 10^{18} 1 \le D \le 10^{18}
しかし、B問題ということもあり数学が苦手な人でも解くことができるよう、いろいろな方法で解ける余地を残しているようにも感じました。そういうわけで、想定解法である数学的な解き方以外のアプローチも考えてみます。
数学的解法
まずは想定解法です。
番号
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, d;
cin >> n >> d;
cout << (n + 2 * d) / (2 * d + 1) << endl;
}
bit全探索
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, d;
cin >> n >> d;
int ans = n;
for (int bit = 0; bit < (1 << n); ++bit) {
vector<bool> is_monitored(n, false);
for (int i = 0; i < n; ++i) {
if (bit & (1 << i)) {
for (int j = max(i - d, 0); j <= min(i + d, n - 1); ++j) {
is_monitored[j] = true;
}
}
}
bool is_ok = true;
for (int i = 0; i < n; ++i) {
if (!is_monitored[i]) {
is_ok = false;
}
}
if (is_ok) {
ans = min(ans, __builtin_popcount(bit));
}
}
cout << ans << endl;
}
計算量が
ちなみに木が監視されているかどうかを管理するのに配列ではなくビットを使用すると、計算量を
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, d;
cin >> n >> d;
vector<int> st(n);
for (int i = 0; i < n; ++i) {
int tot = 0;
for (int j = max(i - d, 0); j <= min(i + d, n - 1); ++j) {
tot |= 1 << j;
}
st[i] = tot;
}
int ans = n;
for (int bit = 0; bit < (1 << n); ++bit) {
int parity = 0;
for (int i = 0; i < n; ++i) {
if (bit & (1 << i)) {
parity |= st[i];
}
}
if (__builtin_popcount(parity) == n) {
ans = min(ans, __builtin_popcount(bit));
}
}
cout << ans << endl;
}
実行時間が67msになりました。
動的計画法(DP)
組み合わせの問題なのでDPも有効です。
しかし、割り算を足し算で計算しているだけなのでやや虚無になります。
#include <bits/stdc++.h>
using namespace std;
int main(){
int n, d;
cin >> n >> d;
vector<int> dp(n + 1);
dp[0] = 0;
for (int i = 1; i <= n; ++i) {
if (i >= 2 * d + 1) {
dp[i] = dp[i - (2 * d + 1)] + 1;
}
else {
dp[i] = 1;
}
}
cout << dp[n] << endl;
}
初期化が面倒なので貰うDPで実装しました。
おわりに
OnlineMathContest(OMC)で数学力を高めましょう。
Discussion