struct Heap { int heap[N + 42],Size;//這裏的 N 是宏定義的 Heap(){memset(heap,0,sizeof(heap));Size = 0;}// 構造函數 inline void Insert (const int key) { heap[++Size] = key; int father,i = Size; while((i >> 1)){ father = i >> 1; if(heap[i] < heap[father]) break; heap[i] ^= heap[father] ^= heap[i] ^= heap[father]; i = father; } } inline void maintain(const int increment) { int son,i = 1;heap[1] -= increment; while((i << 1) <= Size){ son = i << 1; if((son | 1) <= Size && heap[son | 1] > heap[son]) son |= 1; if(heap[i] > heap[son]) break; heap[i] ^= heap[son] ^= heap[i] ^= heap[son]; i = son; } } inline int Get() { if(Size == 0) return -1; else if(Size == 1) return heap[Size--]; heap[1] ^= heap[Size] ^= heap[1] ^= heap[Size];--Size; int son,i = 1; while((i << 1) <= Size){ son = i << 1; if((son | 1) <= Size && heap[son | 1] > heap[son]) son |= 1; if(heap[i] > heap[son]) break; heap[i] ^= heap[son] ^= heap[i] ^= heap[son]; i = son; } return heap[Size + 1]; } } H;
而後讓咱們來看一下這個堆支持的基本操做:函數
inline void Insert (const int key)//inline 是一個小優化 { heap[++Size] = key;//直接插入到尾部 int father,i = Size; while((i >> 1)){//向上調整 father = i >> 1; if(heap[i] < heap[father]) break;//大根堆,父親大於兒子 heap[i] ^= heap[father] ^= heap[i] ^= heap[father];//這是一種整形變量交換的方法 i = father;//兒子比父親大,因此交換位置 } }
\(<<\) , \(>>\) 是移位操做
其中 \(a << i\) 至關於 $a \times 2^i $ 。優化
\(a >> i\) 則至關於 \(a \times 2^{-i}\)。spa
1 轉換成二進制是 \(1_{{(000001)}_2}\) ,而 \(1 << 3\) 就是變爲 \({(001000)}_2\) 即 \(2^3 = 8_{{(001000)}_2}\) ,正好移了三位code
移位操做不支持負數,浮點數等,它的速度比常規 \(\times\) ,\(\div\) 要快一點(它是基於二進制的操做)。blog
向上調整其實沒什麼好說的,注意不要越界就是了,時間複雜度 \(\Theta(log_2n)\)rem
inline void maintain(const int increment) { int son,i = 1;heap[1] -= increment; while((i << 1) <= Size){ son = i << 1; if((son | 1) <= Size && heap[son | 1] > heap[son]) son |= 1;//往下就要注意要跟最大的兒子交換,因此若是存在右兒子,就要與之比較,取較大的。 if(heap[i] > heap[son]) break; heap[i] ^= heap[son] ^= heap[i] ^= heap[son]; i = son; } }
\(i | 1\) 在代碼中至關於 \(i + 1\)
原理則是基於移位操做,如:get
\(1_{{(000001)}_2} << 1\) 變爲 \(2_{{(000010)}_2}\) 再與 \(1_{{(000001)}_2}\) 進行或操做 \(_{{(000001)}_2}^{{(000010)}_2}\) 就變成\(3_{{(000011)}_2}\) (二進制位一一對應,只要有一個是 \(1\) 就置爲 \(1\) ) 。string
時間複雜度也是 \(\Theta(log_2n)\) 。io
inline int Get() { if(Size == 0) return -1;//堆是空的。 else if(Size == 1) return heap[Size--];//若是沒有這句的話,當 Size = 1 時,會有問題。 heap[1] ^= heap[Size] ^= heap[1] ^= heap[Size];--Size; int son,i = 1; while((i << 1) <= Size){ son = i << 1; if((son | 1) <= Size && heap[son | 1] > heap[son]) son |= 1; if(heap[i] > heap[son]) break; heap[i] ^= heap[son] ^= heap[i] ^= heap[son]; i = son; } return heap[Size + 1];//返回此前的堆首 }
跟維持操做沒什麼區別,稍微改一下就是的,時間複雜度也是 \(\Theta(log_2n)\)模板
很容易就想到一個貪心的思路,模擬每個小時,對溼度最大那件用烘衣機,烘完之後從新找當前溼度最大的使用,最後獲得的確定是最優的。
因而這道題即可以水(直接用 \(STL\) 也能夠)過去了。
時間複雜度 \(\Theta(nlog_2n)\)
template <typename T> inline void in(T& x) { x = 0; char ch = getchar(); while(ch < '0' || ch > '9') ch = getchar(); while(ch >= '0' && ch <= '9'){x = (x << 3) + (x << 1) + (ch ^ 48);ch = getchar();} }
快速讀入模板
int main() { in(n);in(a);in(b); for(reg int i = 1; i <= n; ++i) H.Insert(Read()); while(H.heap[1] > tim){tim += a;H.maintain(b);} printf("%d",tim/a); return 0; }
用 \(tim\) 來累計當前天然風乾的溼度,\(H.heap[1]\) 是目前溼度最大的衣服。
\(a\) 是天然風乾速度, \(b\) 是烘衣機烘乾速度。
最後輸出 \(tim \div a\) 。
小聲 bb 幾句:除了打表的,我這應該算是很快的。這個題解花的時間比我打正解花的時間久