06:月度开销
題目鏈接:http://noi.openjudge.cn/ch0111/06/
總時間限制: 1000ms 內(nèi)存限制: 65536kB
描述
農(nóng)夫約翰是一個精明的會計師。他意識到自己可能沒有足夠的錢來維持農(nóng)場的運轉(zhuǎn)了。他計算出并記錄下了接下來 N (1 ≤ N ≤ 100,000) 天里每天需要的開銷。
約翰打算為連續(xù)的M (1 ≤ M ≤ N) 個財政周期創(chuàng)建預(yù)算案,他把一個財政周期命名為fajo月。每個fajo月包含一天或連續(xù)的多天,每天被恰好包含在一個fajo月里。
約翰的目標(biāo)是合理安排每個fajo月包含的天數(shù),使得開銷最多的fajo月的開銷盡可能少。
輸入
第一行包含兩個整數(shù)N,M,用單個空格隔開。
接下來N行,每行包含一個1到10000之間的整數(shù),按順序給出接下來N天里每天的開銷。
輸出
一個整數(shù),即最大月度開銷的最小值。
樣例輸入
7 5
100
400
300
100
500
101
400
樣例輸出
500
輸入輸出樣例說明
若約翰將前兩天作為一個月,第三、四兩天作為一個月,最后三天各自作為一個月,則最大月度開銷為500。其他任何分配方案都會比這個值更大。
先看AC代碼:
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<string.h> 4 int check(long *a,long N,long long mid,long M); 5 int main() 6 { 7 long N,M; 8 long *a=NULL,i; 9 long long left=0,right=0,mid=0; 10 int res; 11 12 scanf("%ld%ld",&N,&M); 13 a=(long*)malloc(N*sizeof(long)); 14 memset(a,0,N); 15 for(i=0;i<N;i++) 16 { 17 scanf("%ld",&a[i]); 18 if(a[i]>left) left=a[i]; 19 right=right+a[i]; 20 } 21 22 while(left<right) 23 { 24 mid=left+(right-left)/2; 25 res=check(a,N,mid,M); 26 if(res==1) right=mid; 27 else left=mid+1; 28 } 29 printf("%lld\n",left); 30 return 0; 31 } 32 33 //假設(shè)最大月開銷為mid,統(tǒng)計需要分成多少個月.然后看月的個數(shù)是否太多或太少 34 int check(long *a,long N,long long mid,long M) 35 { 36 long count=1,i,temp=0; 37 for(i=0;i<N;i++) 38 { 39 if(temp+a[i]<=mid) temp=temp+a[i];//把第i天歸入到當(dāng)前第count月 40 else if(a[i]<=mid)//可以獨立成一個月 41 { 42 count++;//開始一個新的月 43 temp=a[i]; 44 if(count>M) return -1;//最大月開銷太小,導(dǎo)致分的組太多了。 45 } 46 else return -1;//最大月開銷mid太小了,導(dǎo)致某些開銷比較大的天單獨構(gòu)成一個月都不行。 47 } 48 if(count>M) return -1; 49 else if(count<=M) return 1;//最大月開銷mid太大了,導(dǎo)致分的組太少了 50 }思路說明:
題目的意思一定要理解清楚!!!“合理安排每個fajo月包含的天數(shù),使得開銷最多的fajo月的開銷盡可能少。” ? “輸出一個整數(shù),即最大月度開銷的最小值。”
就是把所有天劃分為若干個段,先求出每個段里面的數(shù)字之和,然后統(tǒng)計各段累加和的最大值,這個值要盡可能小。現(xiàn)在要找的就是這個“累加和的最大值” ? 最小可以是多少。
?首先,這個題目應(yīng)該二分,因為解的區(qū)間是可以明確的,可以對該區(qū)間進(jìn)行二分求的真正的解。
假設(shè)二分的區(qū)間left~right,其中l(wèi)eft是n天開銷中最大的那一個數(shù)字,right是n天開銷的總和。 ?(設(shè)想一個極限情況,要使得每一個月開銷盡量小,那么每一天都單獨做一個月就好啦,于是這個時候的月開銷最大值就是n天中每天開銷最大的值,所以left可以取max(a1,......,an)。 ? ?再設(shè)想另一種極限情況,把所有天合并在一起組成一個月,那么這個時候月開銷最大值就是sum(a1,a2,......,an),所以right取值就是n天的累加和。)
需要注意的一個地方是二分循環(huán)部分的代碼:
1 while(left<right) 2 { 3 mid=left+(right-left)/2; 4 res=check(a,N,mid,M); 5 if(res==1) right=mid; 6 else left=mid+1; 7 } 8 printf("%lld\n",left);其中l(wèi)eft=mid+1這里必須加上1,否則可能會死循環(huán)的。
另外,輸出值是left。這個地方也要特別注意。(請自己腦補為何是left吧)
關(guān)于子函數(shù)check(),嗯代碼注釋講的很清晰,不說了。
?
轉(zhuǎn)載于:https://www.cnblogs.com/huashanqingzhu/p/5607503.html
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎總結(jié)
- 上一篇: python汉化之后好用吗_Python
- 下一篇: 玩转带外触发的单目相机之一