這道題的貪心好迷啊~
咱們對於兩個過程進行單獨貪心,而後再翻轉一個,把這兩個拼起來.
先說一下單獨貪心,單獨貪心的話就是用一個堆,每次取出最小的,而且把這個最小的加上他單次的,再放進去.這樣,咱們獲得的結果,是對於某些洗衣機,不停地洗,而後把這些洗衣機的時間,混在一塊兒,排個序,因爲對於每一個洗衣機,若是被用到,那麼他就會被不停地用,若是咱們稍做改動,就必定會是用小的換來大的,因此這樣最優.
咱們把兩個拼起來爲何是對的呢.對於兩個單獨的答案,最優的無疑是,翻轉以後拼起來,由於若是不是這樣,也就是說進行了換位,那麼參與交換的原來頂着的甲方的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; }