首先,我們一定可以捨去那些高度比 \(h_1\) 還小的城市,並且將剩餘的高度比 \(h_1\) 大的城市排序,使得 \(h_1\) 到 \(h_n\) 遞增。
我們不妨從三座城市想起。假如可以合併兩次,應該怎麼合併?
先合併 \((1,2)\),再合併 \((2,3)\),因為這樣更多的水被貢獻給了 \(1\),對吧?
由此我們得出了第乙個obeservation:越早合併的城市,高度越低。這也就意味著,我們每次合併的城市,必定是高度遞增的一段,且前一次合併的所有城市的水量都低於後一次合併的城市。
那如果只能合併一次呢?
首先,\((1,3)\) 肯定是要合併的。那麼,\(2\) 要不要並進去呢?這就要看 \((1,3)\) 合併後,\(2\) 是否比 \(1,3\) 的高度高了。
於是我們得到了用一次合併來合併城市 \(1\) 與某段城市 \([l,r]\) 的策略:先合併城市 \(1\) 和 \(r\),然後依次合併 \(r-1,r-2,\dots,l\),直到並進去會使得平均值減小。
有了這兩個觀察,我們就可以開始dp了:設 \(f_\) 表示前 \(i\) 個位置合併 \(j\) 次的最優答案。則 \(f_=\max\limits_\) 還要與 \(f_,f_,\dots,f_\) 取 \(\max\),用來表示位置 \(i\) 不合併到某段區間中。
這種「合併 \(k\) 次」的dp,要優化肯定要按照合併次數dp。於是我們設 \(f_i\) 表示當前的dp陣列,\(g_i\) 表示上一輪dp(合併次數少一)的dp陣列。
則式子修改為 \(f_i=\max\limits_
int main()
printf("%lf\n",f[n]);
return 0;
}然後,有乙個推論是「合併 \([l,r]\) 時實際上是合併了 \([l,r]\) 中一段最優的字尾 \([l',r]\)」這個東西實際上是沒有必要的,因為若 \([l,r]\) 只合併了 \([l',r]\),而 \([l,l'-1]\) 未被合併,但是以 \(l-1\) 結尾的一段區間卻被合併了的話,我們完全可以將它向右移至以 \(l'-1\) 結尾,並使得答案更大。因此,這個結論變換為,所有被合併過的位置是 \(h\) 陣列的一段字尾。(雖然這個結論是我在寫題解時才發現的,因此**中完全沒有用到這個結論)
這之後,我們掏出轉移式 \(f_i=\max\limits_
void solve()
void solve(int id)
for(int i=1;i<=n;i++)if(f[i]}decimal calc(int i,int j)
int main()
decimal res=calc(lim,n-m+lim);
for(int i=n-m+lim+1;i<=n;i++)res=(res+h[i])/2;
cout } 題目傳送門 step1 暴力 對於每次詢問,都進行一次krusal計算。include include define maxn 5039 using namespace std inline intread if flag return sum return sum struct jtz e max... 看到題目,資料範圍有點怪異。對於95 的資料,對於100 的資料,意思是只有5分是正解。好吧,95pts的 很明顯,答案就是 而如何才能拿到100pts呢?我們可以先列舉a段的長度,很明顯每個長度為lcp,與往後求lcs,若 這樣就可以通過 include include include inclu... 題目實際上要求我們求從每個點出發的aa串的數量 考慮點i的答案,發現如果字首i與字首j j i 的最長公共字尾 i j,那麼i點出發向前就存在乙個長度為i j的aa串,題目即求對於每個字首,有多少個在他之前的字首滿足條件 考慮字尾自動機,由於每個字首都是字尾自動機parent樹上的一點,即兩個字首的...國王飲水記 題解
NOI2016 優秀的拆分
NOI2016 優秀的拆分