电池的寿命

GitHub跳转原题关系图返回列表

两节电池同时放电:总电量给出上界 Σ/2,单节速率上限再给出上界 Σ−max,答案取小者,按比例换电即可取到。

OJ: roj

题目 ID: 1229

难度:普及-

标签:贪心数学python

创建: 2026-09-30 00:46

更新: 2026-10-05 06:05

题目描述

游戏机有两个电池槽,必须同时装有电池才能工作;第 ii 节电池能用 aia_i 小时(每小时耗 1 格电量),随时可以换下再换回(剩余电量保留)。输入多组数据,每组第一行是电池数 NN(2⩽N⩽10002 \leqslant N \leqslant 1000),第二行是 NN 个正整数 aia_i。对每组数据输出最长连续使用时间,保留 1 位小数。样例:输入 2 / 3 5 输出 3.0;输入 3 / 3 3 5 输出 5.5。

思路

设总电量 Σ\Sigma、最大电量 MM,答案 T=min⁡(Σ/2, Σ−M)T = \min(\Sigma/2,\ \Sigma - M):两槽每小时合计耗 2 格给出 T⩽Σ/2T \leqslant \Sigma/2;单节每小时最多耗 1 格、其余电池共 Σ−M\Sigma - M 格要撑起另一半,给出 T⩽Σ−MT \leqslant \Sigma - M。两个上界都能通过"按比例换电"构造取到(M⩽Σ/2M \leqslant \Sigma/2 时所有电池恰在 Σ/2\Sigma/2 同时耗尽,M>Σ/2M > \Sigma/2 时最大电池以速率 1 放电、其余按比例),故取小者即精确答案,只需一次求和与取最大。

参考代码

Python 版:

python
#!/usr/bin/env python3
# Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
# rbook: -> https://rbook.roj.ac.cn  https://rbook2.roj.ac.cn
# rainboy的学习导航网站: https://idx.roj.ac.cn
# create_at: 2026-09-30 00:46
# update_at: 2026-09-30 00:46

import sys


def max_playing_time(caps: list[int]) -> float:
    """一组电池能玩的最长时间:两个上界取小。

    总上界 total/2:两个槽每小时各耗 1,总耗电 = 2T 不超过总电量。
    上界 total - max:若最大电池独大(max > total/2),它跑满速率 1 也只能贡献 T,
    其余电池的总电量必须撑起另一半且不能中途死光,故 T 不超过其余电量之和。
    """
    total = sum(caps)
    return min(total / 2, total - max(caps))


def solve() -> None:
    data = iter(map(int, sys.stdin.buffer.read().split()))
    out: list[str] = []
    for n in data:  # 多组数据读到 EOF,n 是题面格式里的电池数目
        caps = [next(data) for _ in range(n)]  # 每节电池能用的小时数
        out.append(f"{max_playing_time(caps):.1f}")

    print('\n'.join(out))


if __name__ == "__main__":
    solve()

C++ 版(同一算法):

cpp
/**
 * Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
 * rbook: -> https://rbook.roj.ac.cn  https://rbook2.roj.ac.cn
 * rainboy的学习导航网站: https://idx.roj.ac.cn
 * create_at: 2026-10-05 06:05
 * update_at: 2026-10-05 06:05
 */

#include <cstdio>
#include <algorithm>
using namespace std;

typedef long long ll;

const int MAXN = 1005;

ll a[MAXN]; // a[i] 表示第 i 节电池能使用的小时数

int main() {
    int n;
    // 多组数据读到 EOF
    while (scanf("%d", &n) == 1) {
        ll sum = 0;   // 总电量 Sigma
        ll mx = 0;    // 最大单节电量 M
        for (int i = 1; i <= n; i++) {
            scanf("%lld", &a[i]);
            sum += a[i];
            mx = max(mx, a[i]);
        }
        // 两个上界取小:总电量给 T <= sum/2,单节速率 1 给 T <= sum - max
        // sum 是整数,min 结果要么是 .0 要么是 .5,直接用整数运算换算成 0.1 位输出
        ll t2 = min(sum, 2 * (sum - mx)); // 相当于 2T,避免浮点
        printf("%lld.%c\n", t2 / 2, (t2 % 2 == 0) ? '0' : '5');
    }
    return 0;
}