https://ac.nowcoder.com/acm/contest/886/D
思路:这题不能用二分,因为是不能证明是单调的,读完题发现跟HUD 2795 好像,就直接用线段树来寻找最小的箱子了。
AC代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define lson l, m, rt << 1 4 #define rson m + 1,r, rt << 1 | 1 5 #define lst rt << 1 6 #define rst rt << 1 | 1 7 #define lr2 (l + r) >> 1 8 const int maxn = 1e4+5; 9 const int INF = 0x3f3f3f3f; 10 typedef long long ll; 11 int n, k; 12 int a[maxn]; 13 int sum[maxn << 2]; 14 void up(int rt) 15 { 16 sum[rt] = max(sum[rst],sum[lst]); 17 } 18 void build(int v, int l, int r, int rt) 19 { 20 sum[rt] = v; 21 if(l == r) return; 22 int m = lr2; 23 build(v, lson); 24 build(v, rson); 25 } 26 void query(int x, int l, int r, int rt) 27 { 28 if(l == r) 29 { 30 sum[rt] -= x; 31 return ; 32 } 33 int m = lr2; 34 if(sum[lst] >= x) query(x, lson); 35 else query(x, rson); 36 up(rt); 37 return ; 38 } 39 bool check(int mid) 40 { 41 bool flag = true; 42 build(mid, 1, k, 1); 43 for(int i = n;i >= 1;i--) 44 { 45 if(sum[1] < a[i]) 46 { 47 flag = false; 48 break; 49 } 50 else query(a[i], 1, k, 1); 51 } 52 return flag; 53 } 54 int main() 55 { 56 int t; 57 scanf("%d",&t); 58 int cnt = 1; 59 while(t--) 60 { 61 scanf("%d%d",&n,&k); 62 int r = 0; 63 int l = 0; 64 for(int i = 1;i <= n;i++) 65 { 66 scanf("%d",&a[i]); 67 r += a[i]; 68 l = max(l,a[i]); 69 } 70 sort(a + 1,a+n +1); 71 l = max(l,r / k); 72 while(!check(l)) l++; 73 printf("Case #%d: %d\n",cnt++,l); 74 } 75 return 0; 76 }