线性DP-洛-同数字合并

P3147 [USACO16OPEN] 262144 P

题目描述

贝西喜欢在手机上下载游戏来玩,尽管她确实觉得对于自己巨大的蹄子来说,小小的触摸屏用起来相当笨拙。

她对当前正在玩的这个游戏特别感兴趣。游戏开始时给定一个包含 \(N\) 个正整数的序列(\(2 \leq N \leq 262,144\)),每个数的范围在 \(1 \ldots 40\) 之间。在一次操作中,贝西可以选择两个相邻且相等的数,将它们替换为一个比原数大 1 的数(例如,她可以将两个相邻的 7 替换为一个 8)。游戏的目标是最大化最终序列中的最大数值。请帮助贝西获得尽可能高的分数!

输入格式

第一行输入包含 \(N\),接下来的 \(N\) 行给出游戏开始时序列的 \(N\) 个数字。

输出格式

请输出贝西能生成的最大整数。

输入输出样例 #1

输入 #1

4
1
1
1
2

输出 #1

3

说明/提示

在示例中,贝西首先合并第二个和第三个 1,得到序列 1 2 2,然后将两个 2 合并为 3。注意,合并前两个 1 并不是最优策略。

想法

其实这个数字范围很小,想得到把能合成的数字当成一个维度,但是dp存什么不知道。一开始想到石子合并,用区间dp,但其实有用信息不用存这么多,数据范围也太大。后来想模拟这个合并过程,从枚举到当前数开始,每次合并多要一步步跟前面的数合并,要计算出区间长度,因此dp[i][j]可以存以i结尾合成j的区间长度,这样一步步合并也有信息找到前面的区间合并。
代码:

点击查看代码
#include <bits/stdc++.h>
using namespace std;
int n,ans;
int a[270000];
int dp[270000][60];    //以i结尾到达最大j所用连续长度
int main()
{
    cin>>n;
    for(int i = 1;i <= n;i++)    
    {
        cin>>a[i];
        dp[i][a[i]] = 1;
    }
    for(int i = 1;i <= n;i++)
    {
        int pre = i-1,cnt = a[i];
        while(dp[pre][cnt] > 0)
        {
            dp[i][cnt+1] = dp[i][cnt] + dp[pre][cnt];
            pre = i-dp[i][cnt+1];
            cnt++;
            //cout<<pre<<' '<<cnt<<endl;
        }
        ans = max(ans,cnt);
    }
    cout<<ans;
    return 0;
}
posted @ 2026-08-14 12:16  lucky_lh  阅读(7)  评论(0)    收藏  举报