從一個錯了一整天的"一眼題"說起 (二分,洛谷P1182 數列分段 Section II)
部落格要寫的整潔。氣質是修煉不來的啊,體現在方方面面。
當代碼越來越長的時候,當你又需要這樣特判那樣特判的時候……
你幾乎已經錯了。_(:з」∠)_
再改改不出來只能說之前想出的演算法不適合吧……部落格寫工整一點
【二分】
最後想拿到的肯定是m=cnt&&rec=mid的,但是這個並不需要特判返回。
r<l的時候迴圈幾乎已經退出了呀,我們需要的ans
emmm...錯了一天 每次都有新的錯法
啊~ 如果一個題想要二分要滿足二分性的。
就是說,一長串,一半可以,另一半不行,我們二分的是那個分界線
可以的是滿足題意,但是多了,不可以的就是真的不可以。
我在上個題目“數的座標、扔石子”中的,前面不行後面不行中間去分吧,的解法,其實充其量只是一個列舉和縮小範圍的界限而已。要理解二分的本質,即是就是是,不是就是不是,不要這樣模稜兩可。
本題要二分的不是那個最大值,而是在滿足多少的前提下可以分成恰好m塊。
至於細節,如果分成了2塊(題目要求是3塊)那麼一定可以拆成3塊,只是沒拆的問題。即2是滿足條件的那一方,2的話就是分塊數量太少,因為最大值太大。
由此。題目中,右邊(上面)是可行的,下面(左邊)是不可行的,相應的二分程式也要改。
在抽同學二分模板中,cmp判斷為真(條件可行)時才更新。一併更改便好。
恭喜我在抽同學的瘋……狂提示下終於會了一點點二分。
他說這個很簡單的,程式碼肯定不超過20行。我。。
最後寫成這樣還行吧-、- (過程要理解,上面邊界是啥,下面邊界是啥。(⊙_⊙))
#include<algorithm> #include<vector> #include<iostream> #include<queue> #include<stdio.h> using namespace std; int a[100005]; int n, m; int cmp(int mid) { int temp = 0; int cnt = 0; for (int i = 1; i <= n; i++) { if (temp + a[i] <= mid)temp = temp + a[i]; else if (temp + a[i]>mid){ cnt++; temp = a[i]; } }if (temp != 0)cnt++; if (cnt>m)return 0; return 1; } int main() { cin >> n >> m; int kkk = 0; int sum = 0; for (int i = 1; i <= n; i++) { cin >> a[i]; sum += a[i]; kkk = max(kkk, a[i]); } int l = kkk; int r = sum;int ans = 0; while (l <= r) { int mid = (l + r) / 2; int xxx = cmp(mid); if (xxx == 1){ r = mid - 1; ans = mid; } else l = mid + 1; } cout << ans << endl; return 0; }
【動態規劃】
前面做的。
(1)dp[0][0]=1
(2)在任何情況停下來都是最優解法
(3)此種情況可由正好兩種情況推理而來/ 有兩種可以促使它拿到今天的結果
(4)二維狀態下座標表示的是什麼
如本題中dp[i][j]即第i秒在位置j處。想出了這一點繼續推理也不復雜了
***記憶化搜尋。
若更新過記錄肯定不等於0,直接返回即可。【否則每次訪問到都需要重新遞迴!!!!】
簡單的一小句話救了TLE的命。
30*30的範圍啊,,,