Algorithm Notes

LJXin

记录算法刷题、竞赛思路与编程成长,希望每一篇都讲清楚一点、写扎实一点。

P9749 [CSP-J 2023] 公路

P9749 [CSP-J 2023] 公路

原题链接

题目范围

\(1 \leq n \leq 10^5\)\(1 \leq d \leq 10^5\)\(1 \leq v_i \leq 10^5\)\(1 \leq a_i \leq 10^5\)

解题思路

\(d\): 车每升油可以前进的距离

\(v_i\): 站点间的距离

\(a_i\): 加油的价格

\(n-1\) 段路,油箱是无限大的。如果分段考虑买油量,答案会偏大,因为加油量是整数且油是可以延续的。

因此,我们从整体出发,考虑每段路必须买的油,即上一段路“多余”的油用完后,在下一站到前还要用的油量。

引入前缀和 prv[i] 表示前 \(i\) 段路的总路程,\(\lceil \frac{\text{prv}[i]}{d} \rceil\) 表示到达 \(i+1\) 站点至少需要的油量,\(\lceil \frac{\text{prv}[i-1]}{d} \rceil\) 表示到达第 \(i\) 站至少需要的油,两者相减即表示在 \(i \sim i+1\) 段必须买的油。

考虑到价格,我们可以在第 \(i+1\) 站以前的最便宜的站把这个油买了(贪心),即最终结果就是对每一段新增油量乘以前面的最小油价后求和。

复杂度分析

时间复杂度:\(O(n)\)

空间复杂度:\(O(n)\)

代码实现

void solve(){
    int n,d;
    cin>>n>>d;
    vector<int>v(n); //1 ~ n-1
    vector<LL>prv(n,0);// prv[1]=pre[0]+v[1]
    vector<int>a(n+1);

    rep(i,1,n) cin>>v[i];
    rep(i,1,n+1) cin>>a[i];
    rep(i,1,n) prv[i]=prv[i-1]+v[i];// 最多为前n-1段路

    int mn=a[1];//维护当前遇见的最低油价
    LL res=0;
    LL need=0;
    rep(i,1,n){
        need=(prv[i]+d-1)/d - (prv[i-1]+d-1)/d; //新增的必须买的油量
        //a/b向上取整为(a+b-1)/b
        mn=min(a[i],mn);
        res+=mn*need;
    }
    cout<<res<<'\n';
}
posted @ 2026-03-31 01:17  kliu_365  阅读(39)  评论(0)    收藏  举报
TOP