「CF505C」 Mr. Kitayuta, the Treasure Hunter

题意

在数轴上有 n n n 块宝石,当你走到一个点时,可以获得点上所有的宝石。

若前一步走了 c c c 个单位长度,那么下一步可以走 c − 1 , c , c + 1 c-1,c,c+1 c1,c,c+1 个单位长度。

你最开始在原点,可以向右走 d d d 个单位长度,求最多可获得多少宝石。

分析

f i , j f_{i,j} fi,j 表示在第 i i i 个点,上一步走 j j j 个单位长度可获得的最大宝石数。

但是 n , p i n,p_i n,pi 的范围是 3 × 1 0 4 3\times 10^4 3×104,二维数组会 MLE,考虑怎么优化。

因为最远的宝石在 3 × 1 0 4 3\times 10^4 3×104,设步数变化 x x x 次,则最大的 x x x 满足 ( 2 d + x ) ( x + 1 ) 2 ≤ 3 × 1 0 4 \frac{(2d+x)(x+1)}{2}\le 3\times 10^4 2(2d+x)(x+1)3×104,解得 x x x 不会超过 300 300 300

更改一下状态,设 f i , j f_{i,j} fi,j 表示在第 i i i 个点, d d d 变化了 j j j 次所能得到的最大宝石数。

总时间复杂度 O ( 300 n ) O(300n) O(300n)

Code

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
inline ll read(){ll x=0,f=1;char c=getchar();while(c<48||c>57){if(c==45)f=0;c=getchar();}while(c>47&&c<58)x=(x<<3)+(x<<1)+(c^48),c=getchar();return f?x:-x;}
const ll maxn=30000,inf=400;
ll n,d,f[maxn+5][inf*2+5],cnt[maxn+5],ans;
signed main(){
    n=read(),d=read();
    for(ll i=1;i<=n;++i)++cnt[read()];
    for(ll i=0;i<=maxn;++i){
        for(ll j=-inf;j<=inf;++j){
            f[i][inf+j]=LLONG_MIN;
        }
    }
    f[d][inf]=cnt[0]+cnt[d];
    for(ll i=d;i<=maxn;++i){
        for(ll j=-inf;j<=inf;++j){
            if(f[i][inf+j]==LLONG_MIN)continue;
            for(ll k=-1;k<=1;++k){
                ll len=d+j+k;
                if(j+k<-inf||j+k>inf||len<1||i+len>maxn)continue;
                f[i+len][inf+j+k]=max(f[i+len][inf+j+k],f[i][inf+j]+cnt[i+len]);
            }
        }
    }
    for(ll i=0;i<=maxn;++i){
        for(ll j=-inf;j<=inf;++j){
            ans=max(ans,f[i][inf+j]);
        }
    }
    printf("%lld",ans);
    return 0;
}
  • 5
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值