日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

HW13-二分

發(fā)布時間:2023/12/13 综合教程 30 生活家
生活随笔 收集整理的這篇文章主要介紹了 HW13-二分 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

A:月度開銷

描述

農(nóng)夫約翰是一個精明的會計師。他意識到自己可能沒有足夠的錢來維持農(nóng)場的運轉(zhuǎn)了。他計算出并記錄下了接下來N(1 ≤N≤ 100,000) 天里每天需要的開銷。

約翰打算為連續(xù)的M(1 ≤MN) 個財政周期創(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 ≤MN) 個巖石。

請幫助約翰確定移走這些巖石后,最長可能的最短跳躍距離是多少?

輸入

第一行包含三個整數(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é)

以上是生活随笔為你收集整理的HW13-二分的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。