「ARC168E-Subsegments with Large Sums」题解
E - Subsegments with Large Sums
sol
一个比较不常规的思维转化。
第一眼的想法是 WQS 二分,然后发现不具有凸性。也就是说,如果我们对分出的段数附加贡献,那么最大化和 \(\ge S\) 的段数是无法实现的。
考虑转化,我们二分答案,给定要求 \(x\) 个和 \(\ge S\) 的段数。在此基础上,使得可能一共存在 \(k\) 段。那么我们只需要得到最大可能总段数即可,倘若 \(k\) 不超过这个值则合法。
显然除了给定段之外其余点一点一段最多,问题转化为最小化 \(\ge S\) 的所有段占的点数之和。
整理一下,要求 \(x\) 个符合要求的段,求这些段所占的点数最小可能值。这就是个典型的 WQS 二分了。DP 方程是简单的:
\[f_i=\min (f_{i-1},\min_{\sum\limits_{k=j+1}^i\ge S}f_j+i-j)
\]
\(f\) 显然是单调的,双指针即可。
双 \(\log\) 不知道为什么可能会 T,记忆化一下即可。
code
int n,k;
ll s,a[N],sum[N];
pli f[N];
pli ans[N];
inline pli chchk(ll dlt){
if(~ans[dlt].fir)return ans[dlt];
int lst=-1;
rep(i,1,n){
f[i]=f[i-1];
while(sum[i]-sum[lst+1]>=s)++lst;
if(~lst)chmin(f[i],pli({f[lst].fir+i-lst-dlt,f[lst].sec-1}));
}
return ans[dlt]={f[n].fir,-f[n].sec};
}
inline bool check(ll x){
int l=0,r=n;
while(l<r){
int m=l+r>>1;
if(chchk(m).sec>=x)r=m;
else l=m+1;
}
return chchk(l).fir+x*l<=n-(k-x);
}
inline void Main(){
read(n,k,s);
rep(i,0,n)ans[i]={-1,-1};
rep(i,1,n)read(a[i]),sum[i]=a[i];
rep(i,1,n)sum[i]+=sum[i-1];
int l=0,r=k;
while(l<r){
int m=l+r+1>>1;
if(check(m))l=m;
else r=m-1;
}
put(l);
}

浙公网安备 33010602011771号