題解 P1843 【奶牛曬衣服】

先奉上代碼--本人的手打大根堆。
頭文件須要 (也能夠不要,把構造函數刪了就是)。
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)\)模板

寫完堆來看題目

題目地址:洛谷 P1843

很容易就想到一個貪心的思路,模擬每個小時,對溼度最大那件用烘衣機,烘完之後從新找當前溼度最大的使用,最後獲得的確定是最優的。

因而這道題即可以水(直接用 \(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 幾句:除了打表的,我這應該算是很快的。這個題解花的時間比我打正解花的時間久

人生第二篇題解~依然沒過~

相關文章
相關標籤/搜索