zoukankan      html  css  js  c++  java
  • 2019杭电多校第三场hdu6606 Distribution of books(二分答案+dp+权值线段树)

    Distribution of books

    题目传送门

    解题思路

    求最大值的最小值,可以想到用二分答案。

    对于二分出的每个mid,要找到是否存在前缀可以份为小于等于mid的k份。先求出这n个数的前缀和sum[],dp[i]表示前i个可以构成的最大份数。初始化dp[1~n]为-1,dp[0]为0,转移方程式为:dp[i] = max(dp[j]) + 1,(sum[i] - sum[j] <= mid, dp[j] >= 0, 0 <= j < i)。如果有一个dp[i]>=k,说明mid可以,r=mid,否则l=mid+1。

    但是数据范围很大,直接这么找肯定超时。所以我们要用离散化后的权值线段树来维护。对于i,我们要找的是满足sum[i] - sum[j] <= mid,即sum[j] >= sum[i] - mid的j里最大的dp[j]。所以我们用权值线段树来来维护前i-1个dp的最大值。对于每次二分都清空然后重新建树,按照插入dp[i],对于每次询问只需返回离散化后sum[j]~最大值的范围内的最大dp值。

    代码如下

    #include <bits/stdc++.h>
    #define INF 0x3f3f3f3f
    using namespace std;
    typedef long long ll;
    
    inline int read(){
        int res = 0, w = 0; char ch = 0;
        while(!isdigit(ch)){
            w |= ch == '-', ch = getchar();
        }
        while(isdigit(ch)){
            res = (res << 3) + (res << 1) + (ch ^ 48);
            ch = getchar();
        }
        return w ? -res : res;
    }
    
    const int N = 200005;
    
    ll a[N], b[N];
    struct T{
        int l, r;
        int maxx;
    }tree[N<<2];
    int dp[N];
    int n, m;
    
    void build(int k, int l, int r)
    {
        tree[k].l = l;
        tree[k].r = r;
        tree[k].maxx = -1;
        if(l >= r)
            return;
        int mid = (l + r) / 2;
        build(2*k, l, mid);
        build(2*k+1, mid + 1, r);
    }
    
    void insert(int k, int x, int u)
    {
        if(tree[k].l == tree[k].r){
            tree[k].maxx = max(tree[k].maxx, u);
            return;
        }
        int mid = (tree[k].l + tree[k].r) / 2;
        if(x <= mid)
            insert(2*k, x, u);
        else
            insert(2*k+1, x, u);
        tree[k].maxx = max(tree[2*k].maxx, tree[2*k+1].maxx);
    }
    
    int query(int k, int l, int r)
    {
        if(tree[k].l >= l && tree[k].r <= r)
            return tree[k].maxx;
        int mid = (tree[k].l + tree[k].r) / 2;
        int m1, m2;
        m1 = m2 = -1;
        if(l <= mid)
            m1 = query(2*k, l, r);
        if(r > mid)
            m2 = query(2*k+1, l, r);
        return max(m1, m2);
    }
    
    bool work(ll mid, int k)
    {
        build(1, 0, k);  
        insert(1, lower_bound(b, b + k + 1, 0) - b, 0);
        for(int i = 1; i <= n; i ++){
            int l = lower_bound(b, b + k + 1, a[i] - mid) - b;
            if(l != k + 1)
                dp[i] = query(1, l, k)+ 1;
            else
                dp[i] = -1;
            if(dp[i] == 0)
                dp[i] = -1;
            if(dp[i] >= m)
                return true;
            int x = lower_bound(b, b + k + 1, a[i]) - b;
            insert(1, x, dp[i]);
        }
        return false;
    }
    
    int main()
    {
        int _ = read();
        while(_ --){
            n = read(), m = read();
            ll l = 0, r = 0;
            a[0] = b[0] = 0;
            for(int i = 1; i <= n; i ++){
                ll x = read();
                if(x < 0)
                    l += x;
                if(x > 0)
                    r += x;
                a[i] = a[i - 1] + x;
                b[i] = a[i];
            }
            sort(b, b + n + 1);
            int k = unique(b, b + n + 1) - b - 1;
            ll mid = (l + r) / 2;
            while(l < r){
                if(work(mid, k))
                    r = mid;
                else
                    l = mid + 1;
                mid = (l + r) / 2;
            }
            printf("%lld
    ", mid);
        }
        return 0;
    }
    
  • 相关阅读:
    python读取csv数据(添加列名,指定分隔方式)
    loc_survived
    数据预处理
    hadoop 指令
    pd.concat
    DataFrame
    SQL左连接
    mysql mysql之把查询的结果保存到新表(小知识点)
    啦啦啦啦 mysql 授权
    ArrayList和LinkedList的区别以及优缺点
  • 原文地址:https://www.cnblogs.com/whisperlzw/p/11271290.html
Copyright © 2011-2022 走看看