問題
携帯電話で 件のメッセージを時刻 (ただし、 ) に送らなければならない。 ただし、時刻 にて携帯には 単位の電力しか残っていない。 また、時刻 では携帯の電源はついている。
携帯電話は、 単位時間で 単位の電力を消費する。
また、どの時刻でも携帯の電源を落とし、その後携帯の電源を付けることができる。 この操作には 単位の電力を消費する。
携帯電話の残り電力が 以下になってしまうと、それ以降ではメッセージを送ることができない。
このとき、携帯電話を充電することなく、すべてのメッセージを送信できるかを判定せよ。
入力
まず最初の1行目に、テストケースの個数を表す整数 が与えられる。
その後、 個のテストケースのそれぞれに対して、以下のように入力が与えられる。
- まず最初の1行目に、整数 が与えられる。
- 次の1行に、整数 が順に与えられる。
条件
- 実行時間制限: 2s
- メモリ制限: 512MB
-
- すべてのテストケースにおける の値の合計は を超えない。
-
出力
各テストケースに対し、すべてのメッセージを送信できる場合は YES
を、できない場合は NO
を出力すること。
解法
個目のメッセージを送ってから、 個目のメッセージを送る際には、以下の2通りの操作のいずれかを行うことが考えられます。
- 電源をそのままつけておく: 電力を だけ消費する
- メッセージを送った瞬間に電源を切り、次のメッセージを送る直前に電源を付ける: 電力を だけ消費する
従って、メッセージを送り切るためには、消費電力をなるべく最小限に抑えることが必要なので、このうちの消費電力が小さい方を選んでいくことになります。
このようにして得られる消費電力の総量が よりも小さいときに 個のメッセージをすべて送りきれ、そうでないときにはメッセージを送りきることができないと判定できます。
すなわち、数式に直すと \begin{align} \sum_{i = 1}^{n} \min (a ({m}_{i} - {m}_{i - 1}), \, b) < f \end{align} が成立すればメッセージを送りきれるということになります。
この左辺の値は の計算量で求めることができるので、これは実行時間制限に十分間に合うと言えます。
ソースコード
各テストケースに対して、 個のメッセージすべてを送りきれるかどうかを判定する関数 solve()
を以下のように実装しました。
int n; ll f, a, b, m[int(2e5 + 5)]; bool solve() { // 値の入力 cin >> n >> f >> a >> b; for (int i = 1; i <= n; i++) { cin >> m[i]; } ll c = 0; // c はすべての消費電力量を表す for (int i = 1; i <= n; i++) { c += min(a * (m[i] - m[i - 1]), b); // i 個目のメッセージを送るための消費電力を足していく } return c < f; // c < f であれば、メッセージを送りきれるので、これを返す }