解説
危険度がa以下の橋にするための最小コストをとします。はdpにより計算することができます。
- とする
- を番目の柱を建設するとき、それまでの柱のコストの合計の最小値と定義する
- で初期化する
- (を満たすについて、の最小値+) で更新する
- がである
ここで、区間の最小値を取得する必要がありますが、セグメント木やスライド最小値で求められます。
は広義単調減少なので、二分探索によって問題を解くことができます。全体の計算量はセグメント木解法なら、スライド最小値解法ならです。
実装例(segtree)
#include <bits/stdc++.h>
#include <atcoder/segtree>
using namespace std;
using namespace atcoder;
using ll = long long;
const ll inf = 1LL << 60;
using S = ll;
S op(S a, S b) {
return min(a, b);
}
S e() {
return inf;
}
int main() {
ll n, l, c;
cin >> n >> l >> c;
vector<ll> x(n + 2, 0), y(n + 2, 0);
for(int i = 1; i <= n; ++i) cin >> x.at(i);
for(int i = 1; i <= n; ++i) cin >> y.at(i);
x.at(n + 1) = l;
x.push_back(inf);
auto calcCost = [&](ll maxDist){
int leftIdx = 0;
segtree<S, op, e> dp(n + 2);
dp.set(0, 0);
for(int i = 1; i <= n + 1; ++i){
while(x.at(leftIdx) < x.at(i) - maxDist) leftIdx++;
if(leftIdx < i){
ll tmp = dp.prod(leftIdx, i) + y.at(i);
dp.set(i, tmp);
}
}
return dp.get(n + 1);
};
ll ng = -1, ok = l + 1;
while(ok - ng > 1){
ll mid = (ok + ng) / 2;
if(calcCost(mid) <= c){
ok = mid;
}else{
ng = mid;
}
}
cout << ok << endl;
return 0;
}
実装例(スライド最小値)
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using P = pair<ll, ll>;
const ll inf = 1LL << 60;
int main() {
ll N, L, C;
cin >> N >> L >> C;
vector<ll> X(N), Y(N);
for(int i = 0; i < N; ++i) cin >> X.at(i);
for(int i = 0; i < N; ++i) cin >> Y.at(i);
X.push_back(L);
Y.push_back(0);
//危険度がmaxDist以下の橋の最小コストを計算
auto calcCost = [&](ll maxDist){
deque<P> que;//(pos, cost)、スライド最小値(Sliding Window Minimum)、単調増加列のみもつ
que.push_back(P(0, 0));
vector<ll> dp(N + 1, inf);
for(int i = 0; i <= N; ++i){
//dequeの先頭削除
while(!que.empty() && X.at(i) - que.front().first > maxDist){
que.pop_front();
}
if(!que.empty()){
dp.at(i) = min(dp.at(i), que.front().second + Y.at(i));
}
//dequeに追加
while(!que.empty() && que.back().second >= dp.at(i)){
que.pop_back();
}
que.push_back(P(X.at(i), dp.at(i)));
}
return dp.at(N);
};
//二分探索
ll ng = -1, ok = L + 1;
while(ok - ng > 1){
ll mid = (ok + ng) / 2;
if(calcCost(mid) <= C){
ok = mid;
}else{
ng = mid;
}
}
cout << ok << endl;
return 0;
}
ユーザー解説
ユーザー解説を書くユーザー解説はまだありません。