【状态设计优化DP】Atcoder Beginner Contest E - Work or Rest

文章讨论了一道关于计算工作日最大贡献的动态规划问题。作者分享了自己的困惑和正解思路,正解是通过设定DP[i]为前i天且第i天休假的贡献和,然后用一个指针枚举并利用前缀和在O(1)时间内计算贡献,从而降低转移复杂度。
摘要由CSDN通过智能技术生成

妈的,补完还是感觉很神秘啊

我发现我DP真的就只会写入门题呜呜呜

但是群友说abcA-G都是签到

那我大约连入门题都不会吧QwQ

题意:

一周有n天,每天除了休假就是工作,对于工作日的贡献是Amin(x,y),其中x和y是离前一个假日和后一个假日的距离,问最大贡献加起来是多少,注意哪天是休假哪天是工作是不确定的

思路:

一眼DP

一开始是这样想的:

因为哪天工作不确定,因此直接设dp[i][1]表示工作日的贡献,dp[i][0]是休假日的贡献

其实休假日并没有贡献,所以干脆直接设dp[i]为工作日i的贡献,答案就是求和

然后就不懂啊,怎么转移,因为前面和后面第一个休假日都不确定,那就去枚举两个指针?因为不止一周,怎么去处理,倍增数组吗?

然后就不会了

正解是设dp[i]为前i天且第i天休假的贡献和

感觉这个状态设的很神秘啊,但是仔细想想就会发现很妙,这样枚举一个指针就可以了

看完觉得很难受,这是咋想到的

当状态设计后发现转移的复杂度太高时,试着在状态设计的时候确定一个量,再去转移

然后去考虑转移,转移的时候考虑贡献是怎么算的

枚举完l后就得加上中间工作日的贡献

怎么O(1)算贡献?前缀和就好了

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int mxn=5e3+10;
int n;
int a[mxn],dp[mxn],sum[mxn];
int cost(int l,int r){
    int len=r-l-1;
    return sum[(len+1)/2]+sum[len/2];
}
signed main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i],sum[i]=sum[i-1]+a[i];
    memset(dp,128,sizeof(dp));
    dp[1]=0;
    for(int i=2;i<=n+1;i++){
        for(int j=1;j<i;j++) dp[i]=max(dp[i],dp[j]+cost(j,i));
    }
    cout<<dp[n+1]<<'\n';
}

总结:

当状态设计后发现转移的复杂度太高时,试着在状态设计的时候确定一个量,再去转移

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值