Loj 507 接竹竿 题解
Loj链接:接竹竿
题目大意:
给定一个数组,每次加入一种颜色的数,可以取走与它颜色相同的两个数之间的所有数,问最后取走的所有数中最大和是多少
分析:
第一眼看到的是二分答案,但不知道二分的check()函数怎么写。
没办法,考虑DP(其实是因为我贪心写挂了)
DP如果可以,那么要至少要满足一下几个条件:
- DP前面的选择情况不影响后面的选择情况(前不影响后)
- DP可以转移
时间、空间复杂度等可以以后慢慢优化啦!
尝试一下?
尝试列出转移方程:
这样我们就列出了一个
接下来就考虑优化呗!
优化
- 前缀和优化
易发现,DP方程里有很多类似求
其实,求连续一段值的和,我们可以用前缀和优化啊!
现在方程就是
示例代码(会TLE!):
for(int i=1;i<=n;i++) scanf("%lld",&a[i].y),a[i].y+=a[i-1].y;
for(int i=1;i<=n;i++)
{
dp[i]=dp[i-1];
for(int j=1;j<i;j++)
if(a[i].x==a[j].x) dp[i]=max(dp[i],dp[j-1]+a[i].y-a[j-1].y);
}
考虑进一步优化
发现转移时,只能找与自己颜色相同的进行转移,所以可以把每一个颜色记录下来,省下循环过程。
这可以用链表或者
注意:时间复杂度此时是可以被卡到
代码就不放辣QwQ!
再来看看这个转移方程:
我们可以把
那就只要考虑这个:
用前缀和优化后:
我们稍稍改变一下转移方程顺序:
换句话说,我们只要求出与
这个可以用一个数组记下来啊!
那么只要
时间复杂度:
Code:
//From:201929 #include<bits/stdc++.h> #define L long long using namespace std; struct P{ int x; L y; }a[1000005]; L dp[1000005],maxx[1000005]; signed main() { int n,k; scanf("%d%d",&n,&k); for(int i=1;i<=n;i++) scanf("%d",&a[i].x); for(int i=1;i<=k;i++) maxx[i]=-1e18; for(int i=1;i<=n;i++) scanf("%lld",&a[i].y),a[i].y+=a[i-1].y; for(int i=1;i<=n;i++) { dp[i]=max(dp[i-1],maxx[a[i].x]+a[i].y); maxx[a[i].x]=max(maxx[a[i].x],dp[i-1]-a[i-1].y); } printf("%lld",dp[n]); return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix