1. 程式人生 > 資訊 >寧德時代帶起鋰電上市狂潮:19 家企業衝刺 IPO,有人暴漲有人愁

寧德時代帶起鋰電上市狂潮:19 家企業衝刺 IPO,有人暴漲有人愁

$ \texttt{Introduction} $

一道思維題,但教練說如果不卡常沒有紫題難度,這是為什麼呢?

$ \texttt{Solution} $

考慮到每次詢問水的體積是固定的,我們就只要使溫度 $ \times L$ 的值最大即可。

問題轉換到了這一步,還是很難做,那怎麼辦呢,我們注意到題目中的一個條件:每天早上都會有 $ v_i $ 單位,水溫為 $ t_i $ 的水流進來,而這個條件恰恰是解題的關鍵,也就是水是一定要接的,只是倒水可以在接它之前倒好,也可以在接它之後倒好。

那麼現在就有兩種情況。

之前的溫度比這次水的溫度小

那麼顯然把之前的水倒掉,因為加入水溫度會變大,喪失同等體積水的情況下,溫度低的水喪失的溫度更小。

之前的溫度比這次水的溫度大

也是同理,因為加入水後溫度變小,那麼一定加入以後倒。

到這裡為止,我認為都沒有什麼思維難度,但是接下來,如何實現這個過程就有一些思維難度了,因為我們要滿足加入這次的水之後,體積恰好為 $ L $ ,而這次之前,水的體積不一定要為 $ L $,這是個很難的問題,那怎麼辦呢,當然是看題解啦。

其實是維護一個單調佇列,滿足佇列裡溫度遞增,這樣子每次只要取出隊首,將他倒掉,使得滿足當前的體積為 $ L-v_i $ ,看起來我們還是沒有解決剛才的問題,但是如果我們考慮溫度的混合公式,我們會發現,如果他乘上 $ L $ ,答案是一段一段的熱量的相加,而會破壞這個秩序的只有倒水,如果我們把隊首直接去掉,實際上就是在他倒入的時候直接去掉,而最後兩個數不合並,就說明我們一定是在倒最後一次水之前將他倒了,這樣子最後一次水就與前面幾次倒水的貢獻獨立了,而如果合併,說明是倒了之後才倒水,因為我們把這兩桶水捆綁了,而只有水是同一次倒的才能捆綁,至此,我們所要的操作全部實現。

$ \texttt{Code} $

int main()
{
	//ios::sync_with_stdio(0);cin.tie();cout.tie();
    n=read();L=read();
    for (i=1;i<=n;i++) t[i]=read(),v[i]=read();
    //vol 現在的體積。 
    l=1;r=0;
    for (i=1;i<=n;i++)
        {
        	while ((v[i]+vol>L)&&(l<=r))
        	    {
        	    	lose=min(v[i]+vol-L,q[l].vol);
        	    	hq-=q[l].tmp*lose;
        	    	vol-=lose;q[l].vol-=lose;
        	    	if  (q[l].vol==0) l++;
				}
		    r++;q[r].tmp=t[i];q[r].vol=v[i];hq+=t[i]*v[i];vol+=v[i];
		    while ((l<r)&&(q[r-1].tmp>q[r].tmp))
		           {
		           	  q[r-1].tmp=(q[r-1].tmp*q[r-1].vol+q[r].tmp*q[r].vol)/(q[r-1].vol+q[r].vol);q[r-1].vol+=q[r].vol;r--;
				   }
			printf("%.7lf\n",hq/L);
		    
		}
    return 0;
}