题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6606
题意为在n个数中选m(自选)个数,然后把m个数分成k块,使得每块数字之和最大的最小。
求数字和最大的最小一般都是二分,二分后可以dp来判断合法,dp[i]表示第i个数字最大可以在的块数。则$dp[i]=max(dp[j])+1,{sum[i]-sum[j]<=x}$,sum为前缀和,x为二分的值。
但是这样的复杂度O(n2logn),显然不行。
则可以优化一下dp,dp的合法转移条件是sum[i]-sum[j]<=x,移项为sum[j]>=sum[i]-x。所以将前缀和离散化,然后每次在权值线段树上查询大于等于sum[i]-x的位置的最大值,即是每次转移的最优位置。
然后用答案更新sum[i]位置的权值即可。
1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<string> 5 #include<cmath> 6 #include<vector> 7 #define lson l,mid,i<<1 8 #define rson mid+1,r,i<<1|1 9 using namespace std; 10 typedef long long ll; 11 const ll maxn = 2e5 + 10; 12 const ll inf = 1e18; 13 ll Max[maxn * 4]; 14 ll a[maxn], b[maxn]; 15 void up(ll i) { 16 Max[i] = max(Max[i << 1], Max[i << 1 | 1]); 17 } 18 void build(ll l, ll r, ll i) { 19 Max[i] = -inf; 20 if (l == r) 21 return; 22 ll mid = l + r >> 1; 23 build(lson); 24 build(rson); 25 } 26 void update(ll pos, ll val, ll l, ll r, ll i) { 27 if (l == r) { 28 Max[i] = val; 29 return; 30 } 31 ll mid = l + r >> 1; 32 if (pos <= mid)update(pos, val, lson); 33 else update(pos, val, rson); 34 up(i); 35 } 36 ll query(ll L, ll R, ll l, ll r, ll i) { 37 if (L > R)return -inf; 38 if (L <= l && r <= R) 39 return Max[i]; 40 ll ans = -inf; 41 ll mid = l + r >> 1; 42 if (L <= mid)ans = max(ans, query(L, R, lson)); 43 if (R > mid)ans = max(ans, query(L, R, rson)); 44 return ans; 45 } 46 ll n, k; 47 ll dp[maxn]; 48 bool check(ll x, ll len) { 49 build(1, len, 1); 50 for (ll i = 1; i <= n; i++) { 51 ll pos = lower_bound(b + 1, b + 1 + len, a[i] - x) - b; 52 ll pos2 = lower_bound(b + 1, b + 1 + len, a[i]) - b; 53 dp[i] = query(pos, len, 1, len, 1) + 1; 54 if (a[i] <= x) 55 dp[i] = max(dp[i], 1ll); 56 if (dp[i] >= k) 57 return true; 58 if (dp[i] > 0) 59 update(pos2, dp[i], 1, len, 1); 60 } 61 return false; 62 } 63 int main() { 64 int t; 65 scanf("%d", &t); 66 while (t--) { 67 ll x; 68 scanf("%lld%lld", &n, &k); 69 for (ll i = 1; i <= n; i++) 70 scanf("%lld", &x), a[i] = a[i - 1] + x, b[i] = a[i]; 71 sort(b + 1, b + 1 + n); 72 ll len = unique(b + 1, b + 1 + n) - b - 1; 73 ll l = -inf, r = inf, ans; 74 while (l <= r) { 75 ll mid = l + r >> 1; 76 if (check(mid, len)) { 77 ans = mid; 78 r = mid - 1; 79 } 80 else 81 l = mid + 1; 82 } 83 printf("%lld ", ans); 84 } 85 }