cf505 C. Mr. Kitayuta, the Treasure Hunter(dp)

题意:

整数线段范围为 [0,30000]。有 n 个宝藏分布在一些整点上,位置已知。现从0出发往右跳到d处,接下来每一次可以往右跳上一次跳的步数t或者t-1步或者t+1步。跳到某个位置就能拿走那个位置的全部宝藏。不能跳0步;跳出界就结束。求最多能拿走几个宝藏。

1n,d30000

思路:

首先考虑一种dp:f(i,j) 表示在位置 i 且上一次跳了 j 步的最大价值。那么下一步能走到 i+j1/i+j/i+j+1

从右往左更新,那么 f(i,j)=i+max{f(i+j1,j1),f(i+j,j),f(i+j+1,j+1)}

答案是 f(d,d),即当前位置为 d,上一次跳了 d

下面缩小 j 的范围。上界:每次都多走一步,d+(d+1)+(d+2)++(d+245)0+1+2++245=30135>30000;下界:每次都少走一步,d+(d1)+(d2)++(d245)245+244++1=30135>30000

所以 j[d245,d+245]。把 j 减去 d 再加上 250 之后存进数组。

下面是记忆化搜索的写法

const int N = 30001, D = 250;
int n, d, a[N], f[N][D*2+3];

int dp(int i, int j)
{
    if(j == 0 || i >= N) return 0; //越界
    int &v = f[i][j-d+D]; //平移区间
    if(v == -1) v = a[i] +
        max({dp(i + j-1, j-1), dp(i + j, j), dp(i + j+1, j+1)});
    return v;
}

signed main()
{
    scanf("%d%d", &n, &d);
    while(n--)
    {
        int x; scanf("%d", &x); //宝藏位置
        a[x]++;
    }

    memset(f, -1, sizeof f);

    printf("%d", dp(d, d));
}

posted @   Bellala  阅读(44)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示