[2019杭电多校第三场][hdu6606]Distribution of books(线段树&&dp)

题目链接: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 }
原文地址:https://www.cnblogs.com/sainsist/p/11329338.html