• [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 }
  • 相关阅读:
    poj 2482 Stars in Your Window + 51Nod1208(扫描线+离散化+线段树)
    bzoj 1036: [ZJOI2008]树的统计Count (树链剖分+线段树 点权)
    树链剖分+线段树 单点修改 区间求和 模板
    bzoj 2124 等差子序列 (线段树维护hash)
    hdu 5638 Toposort (拓扑排序+线段树)
    hdu 5195 DZY Loves Topological Sorting (拓扑排序+线段树)
    Codeforces Round #250 (Div. 1) D. The Child and Sequence(线段树)
    hive 显示当前数据库名
    【Linux】ssh-keygen 的使用方法及配置 authorized_key s两台linux机器相互认证
    python email 模块
  • 原文地址:https://www.cnblogs.com/sainsist/p/11329338.html
Copyright © 2020-2023  润新知