1. 程式人生 > >Luogu [P1334] 瑞瑞的木板(手寫堆)

Luogu [P1334] 瑞瑞的木板(手寫堆)

讀取 兩個 oid print ID 手寫 include 只需要 algorithm

其實這個題完全不需要用手寫堆,只需要一遍遍sort就行了……

但是!

為了練習手寫堆,還是用手寫堆做了。

在做本題之前,如果你沒有什麽思路的話,建議先做Luogu的合並果子。

好,假設你已經做過了合並果子了。那麽正式開始本題:

相信許多人都已經知道了這道題就是合並果子,但是還不知道它是怎樣轉化成合並果子的,其實很簡單:比如說9 7 6 5 3,有些同學可能會想:每次我砍最大的,然後剩下的不就少了。其實不然,因為不一定一次只能砍一個,可以砍兩個或兩個以上。不多說,我把上面例子的最優策略講出來大概就知道了。step1:把9+7+6+5+3切成7+6和5+3+9兩部分;step2:把7+6切成7和6;step3:把5+3+9切成5+3和9兩部分:step4:把5+3切成5和3。這時我們再回過頭來看,是不是就是合並果子的步驟?

AC代碼:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
long long x,n,tot,dl[100001],sum;//小根堆 
char c;
void delete_2(long long num)
{
    if(((num<<1)+1)<=tot)
    {
        if(dl[num<<1
]<dl[(num<<1)+1]) { if(dl[num]<dl[num<<1]) return ; else { swap(dl[num],dl[num<<1]); delete_2(num<<1); } } else { if(dl[num]<dl[(num<<1
)+1]) return ; else { swap(dl[num],dl[(num<<1)+1]); delete_2((num<<1)+1); } } } else { if((num<<1)<=tot) { if(dl[num]<dl[num<<1]) return ; else { swap(dl[num],dl[num<<1]); delete_2(num<<1); } } else return ; } return ; } void delete_1()//刪除操作 { dl[1]=dl[tot--]; delete_2(1); } void qcr(long long num) //名字隨便取的 { if(num==1) return ; if(dl[num]<dl[num>>1]) { swap(dl[num],dl[num>>1]); num>>=1; qcr(num); } return ; } void putin(long long x) //添加操作 { dl[++tot]=x; qcr(tot); } void putout() //讀取操作 { printf("%d",dl[1]); return ; } int main() { ios::sync_with_stdio(false); cin>>n; for(int i=1;i<=n;i++) { cin>>x; putin(x); } for(int i=1;i<n;i++) { int q,p; q=dl[1]; delete_1(); p=dl[1]; delete_1(); sum+=p+q; putin(p+q); } cout<<sum; return 0; }

Luogu [P1334] 瑞瑞的木板(手寫堆)