Codeforces 1667B Optimal Partition 数据结构维护dp
文章目录题意题解很有味道的一场比赛,BC两个题的想法都非常精彩。题目链接题意定义一个区间的贡献f(x)f(x)f(x)为该区间的长度乘上该区间所有数之和的符号。问将一个序列分成若干区间的贡献之和的最大值。题解首先可以写出显然的n2n^2n2动态规划做法。dpi=maxj=0i−1dpj+f(j+1,i)dp_i=max_{j=0}^{i-1}dp_j+f(j+1,i)dpi=maxj=0i−1
很有味道的一场比赛,BC两个题的想法都非常精彩。
题目链接
题意
定义一个区间的贡献 f ( x ) f(x) f(x)为该区间的长度乘上该区间所有数之和的符号。问将一个序列分成若干区间的贡献之和的最大值。
题解
首先可以写出显然的 n 2 n^2 n2动态规划做法。
d p i = m a x j = 0 i − 1 d p j + f ( j + 1 , i ) dp_i=max_{j=0}^{i-1}dp_j+f(j+1,i) dpi=maxj=0i−1dpj+f(j+1,i)
分析区间贡献的性质,发现最优解中若 f ( x ) f(x) f(x)的贡献为负,则 x x x的长度最多为1。可以用维护前缀最大值的树状数组或者线段树来完成这个 d p dp dp的优化。
d p i dp_i dpi的初始值设为 d p i − 1 + f ( i , i ) dp_{i-1}+f(i,i) dpi−1+f(i,i),然后用特判处理 [ 1 , i ] [1,i] [1,i]区间之和为正的情况,最后求 d p j = 1 → i dp_{j=1\to i} dpj=1→i中的最大值,维护的时候用 d p x − x dp_x-x dpx−x来更新即可。
注意序列的前缀和要按照大小排序更新,这样就可以通过了,应该没有什么其他问题,谢谢大家。
const int yuzu=5e5;
typedef ll fuko[yuzu|10];
fuko a,c,o,d,zw,dp;
int main() {
for (int t=read();t--;) {
int n=read(),i;
using pli=pair<ll,int>;
vector<pli> v; v.push_back({-yuzu,-yuzu});
*o=*dp=*d=0;
for (i=1;i<=n;++i) o[i]=read()+o[i-1],v.push_back(pli(o[i],-i));
sort(v.begin()+1,v.end());
auto add=[&](int x,ll v) {
for (;x<=n;x+=x&-x) zw[x]=max(zw[x],v);
};
auto query=[&](int x) {
ll ans=-1e6;
for (;x;x&=x-1) ans=max(ans,zw[x]);
return ans;
};
for (i=1;i<=n;++i) d[-v[i].second]=i,zw[i]=-1e6;
for (i=1;i<=n;++i) {
dp[i]=max(dp[i-1]+(o[i]-o[i-1]>0?1:o[i]-o[i-1]<0?-1:0),query(d[i])+i);
if (o[i]>0) dp[i]=i;
add(d[i],dp[i]-i);
}
printf("%lld\n",dp[n]);
}
}
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐


所有评论(0)