lightoj.1048.Conquering Keokradong(二分 + 贪心)
1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 const int inf = 0x3f3f3f3f ; 5 int n , m ; 6 int T ; 7 int a[2000] ; 8 int l , r ; 9 10 bool solve (int mid) 11 { 12 int tmp = 0 , cnt = 0 ; 13 for (int i = 0 ; i < n ; i ++) { 14 tmp += a[i] ; 15 if (tmp > mid) { 16 tmp = a[i] ; 17 cnt ++ ; 18 } 19 } 20 cnt ++ ; 21 return cnt > m ; 22 } 23 24 int main () 25 { 26 //freopen ("a.txt" , "r" , stdin ) ; 27 scanf ("%d" , &T) ; 28 int cas = 1 ; 29 while (T --) { 30 scanf ("%d%d" , &n , &m ) ; 31 n ++ ; m ++ ; 32 l = - inf ; 33 r = 0 ; 34 for (int i = 0 ; i < n ; i ++) { 35 scanf ("%d" , &a[i]) ; 36 l = std::max (a[i] , l ) ; 37 r += a[i] ; 38 } 39 while (l <= r) { 40 int mid = ( l + r ) / 2 ; 41 if (solve (mid) ) l = mid + 1 ; 42 else r = mid - 1 ; 43 } 44 printf ("Case %d: %d\n" , cas ++ , l ) ; 45 int sum = 0 ; 46 int cnt = 0 ; 47 for (int i = 0 ; i < n ; i ++) { 48 sum += a[i] ; 49 if (sum > l) { 50 printf ("%d\n" , sum - a[i]) ; 51 sum = a[i] ; 52 cnt ++ ; 53 } 54 if (m - cnt + i >= n) { 55 printf ("%d\n" , sum ) ; 56 for (int j = i + 1 ; j < n ; j ++) printf ("%d\n" , a[j]) ; 57 break ; 58 } 59 } 60 } 61 return 0 ; 62 }
initial l = max{a[]} , r = sum {a[]} ;
很明显我们要求的x肯定在[l,r]这个区间内。
我们也能很容易求出:当组合后各个堆中最大的x已知时,至少需要走的天数 day。
所以我们令mid = (l + r)/ 2 ; 并求出对应的 day,if day > (k + 1) , 说明x的值应在[mid + 1,r]上 ; else , 便在[l,mid - 1]上(ps:至于为什么day == k + 1是也定位在这一块,是因为我们想令day “minimize”)。
而且因为我们所求的最后x,是指至少需要走的天数,所以很多情况下会比k + 1小,所以输出时应尽量让前面的a[i]相加贴近x,在最后到。。。就单个输出啊a[i]来补到k+1个。