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 几句:除了打表的,我这应该算是很快的。这个题解花的时间比我打正解花的时间久