LOJ #6035.「雅禮集訓 2017 Day4」洗衣服 貪心

這道題的貪心好迷啊~
咱們對於兩個過程進行單獨貪心,而後再翻轉一個,把這兩個拼起來.
先說一下單獨貪心,單獨貪心的話就是用一個堆,每次取出最小的,而且把這個最小的加上他單次的,再放進去.這樣,咱們獲得的結果,是對於某些洗衣機,不停地洗,而後把這些洗衣機的時間,混在一塊兒,排個序,因爲對於每一個洗衣機,若是被用到,那麼他就會被不停地用,若是咱們稍做改動,就必定會是用小的換來大的,因此這樣最優.
咱們把兩個拼起來爲何是對的呢.對於兩個單獨的答案,最優的無疑是,翻轉以後拼起來,由於若是不是這樣,也就是說進行了換位,那麼參與交換的原來頂着的甲方的A和己方的B,必定會被大於等於A的C和大於等於B的D所代替,那麼這個時候答案必定不會變小.那麼爲何咱們兩個單獨的最優答案,在拼接的時候,仍是能拼出來最優的呢,這是由於,就像咱們在上一段說的,咱們的到的最優答案,是無條件最優,也就是說,其餘的答案,沒有一處會比他好.
冷靜地去思考、證實貪心確實是一個不二之選.
(隨機堆的隨機數是1和0輪換的話,好快啊……二叉堆比左偏樹快好多啊……)ui

#include <cstdio>
#include <cstring>
#include <algorithm>
typedef long long LL;
#define read(a) (scanf("%d",&a))
const int L=1000010,N=100010;
struct Heap{
  LL key[N];
  int val[N],n;
  inline void Init(){read(n);}
  inline void build(){
    register int i;
    for(i=1;i<=n;++i)read(val[i]);
    std::sort(val+1,val+(n+1));
    for(i=1;i<=n;++i)key[i]=val[i];
  }
  inline LL top(){return key[1];}
  inline void update(){
    key[1]+=val[1];
    register int index=1,next;
    while(index<=(n>>1)){
      next=index<<1;
      if(next<n&&key[next]>key[next|1])++next;
      if(key[next]>=key[index])return;
      std::swap(key[index],key[next]);
      std::swap(val[index],val[next]);
      index=next;
    }
  }
}Wash,Dry;
LL a[L],b[L];
int l;
inline void Init(){
  read(l);
  Wash.Init(),Dry.Init();
  Wash.build(),Dry.build();
}
inline void work(){
  register int i;
  for(i=1;i<=l;++i){
    a[i]=Wash.top(),Wash.update();
    b[i]=Dry.top(),Dry.update();
  }
}
inline void print(){
  register LL ans=0;
  register int i;
  for(i=1;i<=l;++i)
    ans=std::max(ans,a[i]+b[l-i+1]);
  printf("%lld\n",ans);
}
int main(){
  Init(),work(),print();
  return 0;
}
相關文章
相關標籤/搜索