Official
		
			
				D - Snuke Prime Editorial
			
			by 
		
		
		
			
		
		
			
	
			
				D - Snuke Prime Editorial
			
			by  tatyam
 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:
				
			
