[USACO16OPEN] 262144 P

又是一道根本看不出来是dp的dp题。。。

这道题的dp表示为:dpij,i含义是要组成的数字,j含义是组成i的左端点,dpij整体的含义是组成数字i的右端点,特别注意,左端点为闭区间,右端点为开区间。

知道了这些后,来看看dp推导式,两个i-1能组成一个i的原理,我们找到两个连续的i-1才能拼成一个i,假设拼成i-1数字的左端点为j,则第一个i-1数字右端点就是dpi-1j,知道了左右端点就可知哪一部分是i-1了。第二个数字怎么办呢?因为是相邻,所以肯定是以上一个数字紧挨着来找了,所以是以dpi-1j为左端点,dp【i-1】【dp【i-1】【j】】为右端点。这个右区间也就是合成i的右区间。

为什么还以dpi-1j为左端点,上一次合成第一个i-1不是用过了吗?这就是为什么我们说右区间为开区间。

整体式子为dp[i][j] = dp[i-1][dp[i-1][j]];

代码如下

#include <iostream>
using namespace std;
const int N = 262200;
int a[N], f[60][N], n;
int main()
{
    cin >> n;
    for (int i = 1; i <= n; ++ i ) {
        int x; cin >> x;
        f[x][i] = i + 1;
    }
    
    int ans = 2;
    for (int i = 2; i <= 60; ++ i )
        for (int j = 1; j <= n; ++ j )
            {
                if (!f[i][j])
                    f[i][j] = f[i - 1][f[i - 1][j]];
                if (f[i][j]) ans = i;
            }
        cout << ans << endl;
        return 0;
}

为什么录入数据时候,右端点为i+1,这个也和右端点是开区间有关

还有注意的是,进行dp时候,如果要组成的数字没有右端点,那么我们就取一下看看能不能取到右端点,然后得到答案了后不要写else,这样会错过答案也要写成if判断。

如果要取的数字本来就有就会跳过第一个查找而直接更新答案,还有就是为什么我们凑成的数字i只到60呢?

这是因为即使有262144个数字,但是每个数字最多只有40这么大,即使有262144个40,那么也只能凑成10w多41,而这10w多41,又凑成5w多42,以此类推发现根本凑不出超过60的数字

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学习算法的杨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值