Loj 507 接竹竿 题解

Loj链接:接竹竿


Solution

题目大意:

给定一个数组,每次加入一种颜色的数,可以取走与它颜色相同的两个数之间的所有数,问最后取走的所有数中最大和是多少

分析:

第一眼看到的是二分答案,但不知道二分的check()函数怎么写。

没办法,考虑DP(其实是因为我贪心写挂了)

DP如果可以,那么要至少要满足一下几个条件:

  1. DP前面的选择情况不影响后面的选择情况(前不影响后)
  2. DP可以转移

时间、空间复杂度等可以以后慢慢优化啦!

 尝试一下?

尝试列出转移方程:

dp[i]=max{dp[i1]ci!=cjdp[j1]+k=1ivkk=1j1vkci==cj 

这样我们就列出了一个O(n3)的DP转移方程。

接下来就考虑优化呗!

优化

  1. 前缀和优化

易发现,DP方程里有很多类似求ijvk的,并且每次DP推方程时都要重新计算一遍

其实,求连续一段值的和,我们可以用前缀和优化啊!

现在方程就是O(n2)的了。

示例代码(会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);
}

考虑进一步优化

发现转移时,只能找与自己颜色相同的进行转移,所以可以把每一个颜色记录下来,省下循环过程。

这可以用链表或者vector 实现

注意:时间复杂度此时是可以被卡到O(n2)的!因为并没有剩下转移过程,只是省去了枚举无法转移情况的时间。

代码就不放辣QwQ!

再来看看这个转移方程:

dp[i]=max{dp[i1]ci!=cjdp[j1]+k=1ivkk=1j1vkci==cj 

我们可以把dp[i]的初值赋为dp[i1]

那就只要考虑这个:

dp[i]=max{dp[j1]+k=1ivkk=1j1vkci==cj 

用前缀和优化后:

dp[i]=max{dp[j1]+summ[i]summ[j1]ci==cj 

我们稍稍改变一下转移方程顺序:

dp[i]=max{summ[i]+(dp[j1]summ[j1])ci==cj 

换句话说,我们只要求出与ci相等颜色里,dp[j1]summ[j1] 最大值

这个可以用一个数组记下来啊!

那么只要O(1),就能完成转移

时间复杂度:O(n)

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;
}
复制代码

 

posted @   201929  阅读(107)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
点击右上角即可分享
微信分享提示