洛谷P3049 [USACO12MAR]園林綠化Landscaping

https://www.luogu.org/problem/show?pid=3049
這道題的思路啦,其實還好啦;
但是自己想的時候跟傻逼一樣;
還好又fop_zz給我講了半天;
做這道題目啦,先去做一下洛谷的一題“種樹”
這道題目啦
最本質的思路,就是先計算當前最優答案,加入總答案,然後在之後的計算裏,來更新之前所謂的“最優答案”
比如我們現在在i缺一
那我們花費x的錢補一
之後我們在j多一顆土
那麼我們假如這個土移到i
那當前的答案是不是(j-i)*z-x
當然我們也可以直接運走費用y
那額當前最優解就是min((j-i)*z-x,y)
之後我們枚舉到k又缺了土
假如從j移動到k
那麼答案是不是(k-j)*z-min((j-i)*z-x,y)
當然這個還要和x取一個min

那我們來觀察從i移到j的轉移
(j-i)*z-x
=jz-iz-x
=jz-(iz+x)
這裏的iz其實和j是沒有什麼關係的
這裏的x就是在i的時候的最優解
那麼我們是不是在j的時候對之前所有缺土的點取一個max(iz+x)就是當前最優解了
這個是不是一個堆就可以完成了?
所以我們維護2個堆,一個是多餘,一個數不足
那麼我們算出當前的最優解的時候,把答案放到另一個堆裏面,假如現在的最優解並不是最終答案,那麼就可以通過這個堆體現出來,並且在後面的“當前最優解”裏面減去這個錯誤的最優解,最終保持當前的正確答案
這也是爲什麼a[i],b[i]的值最大隻有10

#include<bits/stdc++.h>
#define Ll long long
using namespace std;
const Ll N=1e5+5;
Ll n,x,y,ans,m1,m2,z;
priority_queue<Ll>Q1;
priority_queue<Ll>Q2;
int main()
{
    scanf("%lld%lld%lld%lld",&n,&x,&y,&z);
    for(Ll j=1;j<=n;j++){
        scanf("%lld%lld",&m1,&m2);
        if(m1<m2)
            for(Ll i=1;i<=m2-m1;i++)
                if(Q1.empty()||j*z-Q1.top()>=x){
                    ans+=x;Q2.push(x+j*z);
                }else{
                    Ll v=Q1.top();Q1.pop();
                    ans+=j*z-v;Q2.push(j*z*2-v);
                }
        else
            for(Ll i=1;i<=m1-m2;i++)
                if(Q2.empty()||j*z-Q2.top()>=y){
                    ans+=y;Q1.push(y+j*z);
                }else{
                    Ll v=Q2.top();Q2.pop();
                    ans+=j*z-v;Q1.push(j*z*2-v);
                }
    }
    printf("%lld",ans);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章