Official
D - Snuke Prime Editorial by tatyam
すぬけプライムは毎日加入及び脱退ができるので、その日支払う料金が \(C\) 円を超えそうならサブスクリプションを利用し、超えないなら利用しないようにするのが最適です。
そこで、
\(s[i]=\) ( すぬけプライムを利用しない場合の \(i\) 日目に支払う料金 )
を求めたいです。
\(i\) の範囲が小さければ いもす法 で求めることができますが、今回は \(i\) の範囲が大きいので、なにか工夫する必要があります。
例えば、以下のようにすれば良いです。
\(a_i\) 日目から \(b_i\) 日目まで利用する \(c_i\) 円のサービスを、
- \(a_i - 1\) 日目と \(a_i\) 日目 の間に料金が \(c_i\) 円上がるイベントが起こる
- \(b_i\) 日目と \(b_i + 1\) 日目 の間に料金が \(c_i\) 円下がるイベントが起こる
と言い換え、これらのイベントを時間でソートします。
そして、 イベントを前から見ていきながら、今何日目を見ているのか と 現在の料金 の変数を更新していくと、 この問題を \(O(N\log N)\) で解くことができます。
また、\(a_i\) と \(b_i\) を座標圧縮し、いもす法を適用できるようにする方法もあります。
回答例 (C++)
#include <bits/stdc++.h>
using namespace std;
using ll = int64_t;
int main(){
ll N, C;
cin >> N >> C;
vector<pair<ll, ll>> event;
for(ll i = 0; i < N; i++){
ll a, b, c;
cin >> a >> b >> c;
event.emplace_back(a - 1, c);
event.emplace_back(b, -c);
}
sort(event.begin(), event.end());
ll ans = 0, fee = 0, t = 0;
for(auto [x, y] : event){
if(x != t){
ans += min(C, fee) * (x - t);
t = x;
}
fee += y;
}
cout << ans << endl;
}
回答例 (Python)
N, C = map(int, input().split())
event = []
for i in range(N):
a, b, c = map(int, input().split())
a -= 1
event.append((a, c))
event.append((b, -c))
event.sort()
ans = 0
fee = 0
t = 0
for x, y in event:
if x != t:
ans += min(C, fee) * (x - t)
t = x
fee += y
print(ans)
posted:
last update: