首页 > 其他分享 >SP685 SEQPAR - Partition the sequence 题解

SP685 SEQPAR - Partition the sequence 题解

时间:2022-10-24 08:34:38浏览次数:69  
标签:SEQPAR return fmx int 题解 sum Partition fmn INF

SP685 SEQPAR - Partition the sequence Solution

目录

更好的阅读体验戳此进入

(建议您从上方链接进入我的个人网站查看此 Blog,在 Luogu 中图片会被墙掉,部分 Markdown 也会失效)

题面

给定 $ n $ 个数的数列 $ a_n $,给定 $ k $,将数列分成 $ k $ 段,满足每一段的元素和不大于 $ m $,求最小的 $ m \(。\) T $ 组数据。

$ 1 \le k \le n \le 1.5 \times 10^4, -3 \times 10^4 \le a_i \le 3 \times 10^4, 1 \le T \le 10 $。

Solution

首先二分答案很显然,二分 $ m $,并验证 $ m $ 是否对于 $ k $ 成立。

然后对于验证 $ m $ 是否成立,我们显然可以想到,对于这样的一个数列和 $ m $,有解的情况下,一定存在一个最小的和最大的块数的划分方案,并且解是存在连续性的,对于最小 $ fmn $ 和最大 $ fmx $ 一定有 $ \forall k \in \left[ fmn, fmx \right] $ 都成立,这个的严谨证明我不会很显然,就不证明了。

The proof is left to the reader.

然后对于求 $ fmn(i) $ 和 $ fmx(i) $,令其为考虑前 $ i $ 个数的合法方案的最小和最大的 $ k $,求个前缀和 $ sum(i) $,显然有如下的 DP 方程:

\[\begin{aligned} fmn(i) = \min(fmn(j) + 1) \quad j \lt i \land sum(j) \le sum(i) - m \\ fmx(i) = \max(fmx(j) + 1) \quad j \lt i \land sum(j) \le sum(i) - m \end{aligned} \]

对于二分的范围,不难想到我们令数列中负数的和为 $ \xi $,正数的和为 $ \epsilon $,那么范围即为 $ \left[ \xi, \epsilon \right] $,我们令这个区间长度为 $ v $。

发现这个东西的复杂度是 $ O(n^2) $ 的,最终复杂度 $ O(T n^2 \log v) $,显然会寄,于是考虑优化 DP。

显然我们发现这个转移时可以优化的,可以考虑写个平衡树然后区间取最大最小值等,但是我不会不好写,于是我们考虑线段树。

普通线段树显然开不下,所以我们要写一个动态开点的权值线段树,其中的叶子节点下标表示 $ sum(i) $ 的值,存的是 $ fmn(i) $ 和 $ fmx(i) $ 的值,然后支持单点修改和区间求 $ \min $ 和 $ \max $。考虑在每次验证的时候新开一个线段树,然后每次查询 $ \left[ sum(i) - m, \inf \right] $ 区间的 $ \min $ 和 $ \max $ 然后 $ +1 $ 作为新的 $ fmn(i) $ 和 $ fmx(i) $,然后再把这两个值插到线段树中对应的 $ sum(i) $ 中,具体实现可以看一下代码,这道题还是挺巧妙的。

对于权值线段树的范围,显然与二分限制相同。

那么最终复杂度为 $ O(T n \log n \log v) $。

Code

#define _USE_MATH_DEFINES
#include <bits/extc++.h>

#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW(arr) void* Edge::operator new(size_t){static Edge* P = arr; return P++;}

using namespace std;
using namespace __gnu_pbds;

mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}

typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;

#define INF 0x3f3f3f3f

template<typename T = int>
inline T read(void);

struct Node{
    Node *ls, *rs;
    int fmn, fmx;
    OPNEW;
}nd[30000000];
void* Node::operator new(size_t){static Node* P = nd; return P++;}
int limMin, limMax;
int N, K;
int a[18000];
int sum[18000];
int fmn[18000], fmx[18000];
Node* rt;
class SegTree{
    private:
        #define MID ((gl + gr) >> 1)
        #define SIZ (gr - gl + 1)
    public:
        void Pushup(Node* p){
            if(!p)return;
            p->fmn = min(p->ls ? p->ls->fmn : INF, p->rs ? p->rs->fmn : INF),
            p->fmx = max(p->ls ? p->ls->fmx : -INF, p->rs ? p->rs->fmx : -INF);
        }
        void Modify(int idx, pair < int, int > val, Node* &p = rt, int gl = limMin, int gr = limMax){
            if(!p)p = new Node{npt, npt, INF, 0};
            if(gl == gr)return tie(p->fmn, p->fmx) = val, void();
            if(idx <= MID) Modify(idx, val, p->ls, gl, MID);
            else Modify(idx, val, p->rs, MID + 1, gr);
            Pushup(p);
        }
        pair < int, int > Query(int l, int r, Node* p = rt, int gl = limMin, int gr = limMax){
            // printf("Querying l = %d, r = %d, gl = %d, gr = %d, val = %d,%d\n", l, r, gl, gr, p ? p->fmn : -114514, p ? p->fmx : 114514);
            if(!p)return {INF, -INF};
            if(l <= gl && gr <= r)return {p->fmn, p->fmx};
            auto L = MID >= l ? Query(l, r, p->ls, gl, MID) : make_pair(INF, -INF);
            auto R = MID + 1 <= r ? Query(l, r, p->rs, MID + 1, gr) : make_pair(INF, -INF);
            return {min(L.first, R.first), max(L.second, R.second)};
        }
}st;
bool Check(int M){
    rt = new Node{npt, npt, INF, -INF};
    fmx[0] = fmn[0] = 0;
    st.Modify(sum[0], {fmn[0], fmx[0]});
    for(int i = 1; i <= N; ++i){
        tie(fmn[i], fmx[i]) = st.Query(sum[i] - M, INF);
        ++fmn[i], ++fmx[i];
        st.Modify(sum[i], {fmn[i], fmx[i]});
    }
    if(fmn[N] <= K && K <= fmx[N])return true;
    return false;
}
int main(){
    int T = read();
    while(T--){
        limMin = limMax = 0;
        N = read(), K = read();
        for(int i = 1; i <= N; ++i)
            a[i] = read(),
            a[i] >= 0 ? limMax += a[i] : limMin += a[i],
            sum[i] = sum[i - 1] + a[i];
        int l = limMin, r = limMax, ans(-1);
        while(l <= r){
            int mid = (l + r) >> 1;
            if(Check(mid))ans = mid, r = mid - 1;
            else l = mid + 1;
        }
        printf("%d\n", ans);
    }
    fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
    return 0;
}

template<typename T>
inline T read(void){
    T ret(0);
    short flag(1);
    char c = getchar();
    while(c != '-' && !isdigit(c))c = getchar();
    if(c == '-')flag = -1, c = getchar();
    while(isdigit(c)){
        ret *= 10;
        ret += int(c - '0');
        c = getchar();
    }
    ret *= flag;
    return ret;
}

UPD

update-2022_10_13 初稿

标签:SEQPAR,return,fmx,int,题解,sum,Partition,fmn,INF
From: https://www.cnblogs.com/tsawke/p/16820315.html

相关文章

  • ABC246Ex 01? Queries 题解
    ABC246Ex01?QueriesSolution目录ABC246Ex01?QueriesSolution更好的阅读体验戳此进入浅谈DDP与广义矩阵乘法(戳此进入)引入例题#1广义矩阵乘法DDP例题#0例题#0.5......
  • ABC246F typewriter 题解
    ABC246FtypewriterSolution目录ABC246FtypewriterSolution更好的阅读体验戳此进入题面SolutionCodeUPD更好的阅读体验戳此进入题面给定$n$个字符串,字符集为小......
  • ABC246D 2-variable Function 题解
    ABC246D2-variableFunctionSolution目录ABC246D2-variableFunctionSolution更好的阅读体验戳此进入题面SolutionCodeUPD更好的阅读体验戳此进入题面存在函数$f......
  • ABC246E Bishop 2 题解
    ABC246EBishop2Solution目录ABC246EBishop2Solution更好的阅读体验戳此进入题面SolutionCodeUPD更好的阅读体验戳此进入题面给定有障碍的网格图,.为空地,#为障碍......
  • LG-P5104 红包发红包 题解
    LG-P5104红包发红包Solution目录LG-P5104红包发红包Solution更好的阅读体验戳此进入UPD更好的阅读体验戳此进入(建议您从上方链接进入我的个人网站查看此Blog,在Luo......
  • ABC246C Coupon 题解
    ABC246CCouponSolution目录ABC246CCouponSolution更好的阅读体验戳此进入题面SolutionCodeUPD更好的阅读体验戳此进入题面$n$个物品第$i$个价格为$a_i$,......
  • The 18th Zhejiang Provincial Collegiate Programming Contest题解
    A.LeagueofLegends水题。点击查看代码#include<bits/stdc++.h>usingnamespacestd;#defineintlonglonginta[6];intb[6];signedmain(){for(......
  • ABC274 题解
    A题目:给定\(A,B\)输出\({B}\over{A}\)保留\(3\)位小数。简答题,和A+Bproblem一样,除一除,保留一下小数。B题目:给定一个\(n\)行\(m\)列由'.'和'#'的方阵,求每列......
  • Lists.partition
    Lists,提供了很多api方便操作。例如:Lists.partition(Listlist,intsize)Lists.partition(Listlist,intsize)将list集合进行切割然后填充到一个List集合里。官方介......
  • 【题解】The 2021 ICPC Asia Macau Regional Contest - E Pass The Ball
    问题描述解释相当于给定一个置换群,求\(\sum\limits_{i=1}^{n}i*b_{i}\)题目分析本题这种传球的关系显然是存在循环节的,先考虑一个大小为\(m\)的环,显然我们可以用......