如果存在负数怎么做
查看原帖
如果存在负数怎么做
644112
Sinktank楼主2024/11/24 12:44

rt。求助,大佬们~

如果必须对aa求解,目前还没想到好的方法。但是如果可以选择aa任意长度的前缀求解,则有O(nlognlogV)O(n\log n\log V)的方法。

fif_{i}a1ia_{1\sim i} 最多可以分多少段,使得每段的和都 mid\le mid

则有转移 fi,j=max(fj+1)f_{i,j}=\max(f_{j}+1),其中 jj 满足 j<i,SiSjmidj<i,S_{i}-S_{j}\le midSSaa 的前缀和数组)。

如果存在 fimf_{i}\ge m,则说明合法,这是因为如果fi>mf_i>m,则必定存在j<ij<i,使得fj=mf_j=m

这里也是为什么难以只对aa求解,因为有负值所以不满足单调性(即fif_i合法fi+1\nRightarrow f_{i+1}也合法),因此如果定义ff为最大分段数则只能求得aa所有前缀的答案,如果要仅求aa的答案,必须将ff所有可能的取值都计算出来,这样还得再乘一个O(n)O(n)

这样时间复杂度是 O(n2logV)O(n^2\log V),时间开销主要再 O(n)O(n) 的转移,考虑优化。

SiSjmid    SjSimidS_{i}-S_{j}\le mid\iff S_{j}\ge S_{i}-mid。我们考虑用 SuS_{u} 作为索引,fuf_{u} 作为值,扔到线段树里。

更新的时候求线段树 (Simid)V(S_{i}-mid)\sim V 的最大值 maxxmaxx,用 maxx+1maxx+1 更新 fif_{i} 即可。

因为 VV 太大,所以要将所有用到的下标(即 SiS_{i} 和所有 SimidS_{i}-mid)离散化。

时间复杂度降至 O(nlognlogV)O(n\log n\log V)

也可以用树状数组代替线段树,虽然树状数组无法维护区间最大值,但是每次询问的区间都是一个后缀,所以只需要反向建立树状数组即可,码量和速度上都优于线段树。

线段树实现:https://paste.ubuntu.com/p/NKCTF6TVkK/

树状数组实现:https://paste.ubuntu.com/p/wsBNqzgtxf/

2024/11/24 12:44
加载中...