HW13-二分
A:月度開銷
描述
農(nóng)夫約翰是一個精明的會計師。他意識到自己可能沒有足夠的錢來維持農(nóng)場的運轉(zhuǎn)了。他計算出并記錄下了接下來N(1 ≤N≤ 100,000) 天里每天需要的開銷。
約翰打算為連續(xù)的M(1 ≤M≤N) 個財政周期創(chuàng)建預算案,他把一個財政周期命名為fajo月。每個fajo月包含一天或連續(xù)的多天,每天被恰好包含在一個fajo月里。
約翰的目標是合理安排每個fajo月包含的天數(shù),使得開銷最多的fajo月的開銷盡可能少。
輸入
第一行包含兩個整數(shù)N,M,用單個空格隔開。
接下來N行,每行包含一個1到10000之間的整數(shù),按順序給出接下來N天里每天的開銷。
輸出
一個整數(shù),即最大月度開銷的最小值。
樣例輸入
7 5 100 400 300 100 500 101 400
樣例輸出
500
提示
若約翰將前兩天作為一個月,第三、四兩天作為一個月,最后三天每天作為一個月,則最大月度開銷為500。其他任何分配方案都會比這個值更大。
1 #include<iostream>
2 using namespace std;
3 int a[100005];
4 int n, m;
5 bool check(int mid){
6 int cursum = 0;
7 int temp = 1; //注意是1
8 for(int i = 0; i < n; i++){
9 if(cursum+a[i]>mid){ //超了
10 temp++; //fajo月
11 cursum = a[i];
12 }
13 else cursum += a[i];
14 }
15 if(temp > m) return false;
16 return true;
17 }
18 int main(){
19 cin>>n>>m;
20 int l = 0, r = 0;
21 for(int i = 0; i < n; i++){
22 cin>>a[i];
23 l = max(l, a[i]);
24 r += a[i];
25 }
26 int mid;
27 while(l <= r){
28 mid = l + (r-l)/2;
29 bool flag = check(mid);
30 if(flag) r = mid-1;
31 else l = mid+1;
32 }
33 cout<<mid<<endl;
34 return 0;
35 }
備注:二分的題都很套路。首先是卡范圍,最小的可能值顯然就是最多的一天,最大的可能值是所有天之和。然后就是check函數(shù),怎么驗證一個解對不對,一般就用到貪心。注意括號里是l<=r,否則假如答案是50,l是50,r是52,mid是51,check過了之后r變?yōu)?0,不滿足l<r直接退出了,那么答案就不是最小的。這道題就是盡可能把更多的天塞進一個fajo。因為一個月如果本可以塞前一個fajo里卻沒塞,相當于一種浪費,因為它就要占據(jù)后面的空間。這樣塞完之后得到的fajo月如果小于等于我們正在嘗試的mid就是一個可行的解。
B:派
描述
我的生日要到了!根據(jù)習俗,我需要將一些派分給大家。我有N個不同口味、不同大小的派。有F個朋友會來參加我的派對,每個人會拿到一塊派(必須一個派的一塊,不能由幾個派的小塊拼成;可以是一整個派)。
我的朋友們都特別小氣,如果有人拿到更大的一塊,就會開始抱怨。因此所有人拿到的派是同樣大小的(但不需要是同樣形狀的),雖然這樣有些派會被浪費,但總比搞砸整個派對好。當然,我也要給自己留一塊,而這一塊也要和其他人的同樣大小。
請問我們每個人拿到的派最大是多少?每個派都是一個高為1,半徑不等的圓柱體。
輸入
第一行包含兩個正整數(shù)N和F,1 ≤ N, F ≤ 10 000,表示派的數(shù)量和朋友的數(shù)量。
第二行包含N個1到10000之間的整數(shù),表示每個派的半徑。
輸出
輸出每個人能得到的最大的派的體積,精確到小數(shù)點后三位。
樣例輸入
3 3 4 3 3
樣例輸出
25.133
1 #include<iostream>
2 #include<cmath>
3 using namespace std;
4 double a[10005];
5 int n, f;
6 //注意數(shù)據(jù)類型是double
7 const double pi = acos(-1); //求派的巧妙方法
8 bool check(double mid){
9 int temp = 0;
10 for(int i = 0; i < n; i++)
11 temp += a[i]/mid;
12 return temp >= f+1; //別忘了加上自己
13 }
14 int main(){
15 cin>>n>>f;
16 double l = 0, r = 0;
17 int semi;
18 for(int i = 0; i < n; i++){
19 cin>>semi;
20 a[i] = pi * semi * semi; //存體積
21 r = max(r, a[i]);
22 }
23 double mid;
24 while(r-l > 1e-5){
25 mid = l + (r-l)/2;
26 bool flag = check(mid);
27 if(flag) l = mid;
28 else r = mid;
29 }
30 printf("%.3lf", mid);
31 return 0;
32 }
備注:這道題要注意的就是輸入數(shù)據(jù)是半徑,但問的是體積(高是1,所以相當于面積),所以數(shù)組里要存的也是面積。還有一點就是所有的數(shù)據(jù)類型都要是double!最開始我就是忽略了形參mid也應該是double所以得不出正確答案。既然是double,就不能用簡單的=或者<>,而要用ε,這里取的是1e-5。
C:河中跳房子
描述
每年奶牛們都要舉辦各種特殊版本的跳房子比賽,包括在河里從一個巖石跳到另一個巖石。這項激動人心的活動在一條長長的筆直河道中進行,在起點和離起點L遠(1 ≤L≤ 1,000,000,000) 的終點處均有一個巖石。在起點和終點之間,有N(0 ≤N≤ 50,000) 個巖石,每個巖石與起點的距離分別為Di(0 <Di<L)。
在比賽過程中,奶牛輪流從起點出發(fā),嘗試到達終點,每一步只能從一個巖石跳到另一個巖石。當然,實力不濟的奶牛是沒有辦法完成目標的。
農(nóng)夫約翰為他的奶牛們感到自豪并且年年都觀看了這項比賽。但隨著時間的推移,看著其他農(nóng)夫的膽小奶牛們在相距很近的巖石之間緩慢前行,他感到非常厭煩。他計劃移走一些巖石,使得從起點到終點的過程中,最短的跳躍距離最長。他可以移走除起點和終點外的至多M(0 ≤M≤N) 個巖石。
請幫助約翰確定移走這些巖石后,最長可能的最短跳躍距離是多少?
輸入
第一行包含三個整數(shù)L, N, M,相鄰兩個整數(shù)之間用單個空格隔開。
接下來N行,每行一個整數(shù),表示每個巖石與起點的距離。巖石按與起點距離從近到遠給出,且不會有兩個巖石出現(xiàn)在同一個位置。
輸出
一個整數(shù),最長可能的最短跳躍距離。
樣例輸入
25 5 2 2 11 14 17 21
樣例輸出
4
提示在移除位于2和14的兩個巖石之后,最短跳躍距離為4(從17到21或從21到25)。
1 #include<iostream>
2 using namespace std;
3 int a[50005];
4 int L, n, m;
5
6 bool check(int mid){
7 int last = 0;
8 int temp = 0;
9 for(int i = 0; i <= n; i++){
10 if(a[i]-last<mid){
11 temp++; //移走
12 continue;
13 }
14 last = a[i];
15 }
16
17 if(temp > m) return false;
18 return true;
19 }
20 int main(){
21 cin>>L>>n>>m;
22 int r = L, l = 0;
23 for(int i = 0; i < n; i++){
24 cin>>a[i];
25 }
26 a[n] = L;
27 int mid, ans;
28 while(l <= r){
29 mid = l + (r-l)/2;
30 bool flag = check(mid);
31 if(flag){
32 l = mid+1;
33 ans = mid;
34 }
35 else r = mid-1;
36 }
37 cout<<ans<<endl;
38 return 0;
39 }
備注:這道題和我多年前寫過的跳石頭是一樣的,好像是noip真題。但是首先是我又不會了,其次是我發(fā)現(xiàn)當時寫的有一點小錯(沒考慮最后一塊磚),過了是因為數(shù)據(jù)水……要注意的第一點是要把a[n] = L也就是最后一塊石頭補上。(最后一塊石頭是移不了的,但這不影響結(jié)果,因為在check的時候,如果發(fā)現(xiàn)a[n]-last不合要求,移走的其實是last那塊石頭。因為last距離倒數(shù)第三塊石頭一定是滿足要求的,移走它,倒數(shù)第三塊石頭離最后一塊石頭肯定也是足夠的)。
還有一點是上次也強調(diào)過的。這道題的答案寫mid就不行,舉個例子,如果答案是51,l是50,r是52,那么mid是51,然后check過了,l變成52,l依然<=r,這個時候依然進入循環(huán),mid是52,但mid可能沒通過check,這個時候r變成51,跳出了循環(huán),但這個時候mid就不是正確答案。解決辦法就是設置一個ans,保證是check過的。
總結(jié)
- 上一篇: 淘宝客推广链接如何转换?
- 下一篇: ARM Trusted Firmware