BUY LOW, BUY LOWER

BUY LOW, BUY LOWER的代码+解释,主要参考POJ BUY LOW, BUY LOWER,比原文多了些注释和自己的理解

程序主要分为3部分:

  • 求以num[i] 结尾的最长下降子序列的长度dp
  • 求以num[i] 结尾的不重复的最长下降子序列的方案数 project
  • 选择最大的dp值,并求该dp值对应的方案数之和

注:该程序没有实现高精度的计算,所以不适用于数目较多的数据集

#include <stdio.h>
#define N 5005

int num[N];
int dp[N]; // 以num[i]结尾的最长下降子序列的长度
int project[N]; // 以num[i] 结尾的不重复的最长下降子序列的方案数目

int main()
{
    int n;
    while(scanf("%d", &n)){
        for (int i = 1; i <= n; ++i)
        {
            scanf("%d", &num[i]);
            // 初始化dp, project
            dp[i] = 1;
            project[i] = 0;
        }
        // 计算dp,dp[i] = max(dp[j]) + 1
        for (int i = 2; i <= n; ++i)
        {
            int tempLen = 0;
            for (int j = 1; j < i; ++j)
            {
                if(num[j] > num[i] && tempLen < dp[j]){
                    tempLen = dp[j];
                }
            }
            // 就算没有一个能满足以上条件的,num[i]的dp[i]也是1
            dp[i] = tempLen + 1;
        }
        // 计算project, project[i] = sigma(project[j])
        // 这样初始化的意义?dp[i] == 1的情形是产生其他下降子序列的基础,所以要初始化为1
        for (int i = 1; i <= n; ++i)
            if(dp[i] == 1)
                project[i] = 1;
        for (int i = 2; i <= n; ++i)
        {
            for (int j = i - 1; j > 0; --j)
            {
                // 一般情况
                if(num[j] > num[i] && dp[j] + 1 == dp[i]){
                    project[i] += project[j];
                }
                // 特殊情况:遇到数字相同的情况
                if(num[j] == num[i]){
                    // 在dp[i] == 1的时候(也就是处在最长下降子序列的初始阶段(第一个数)),为了避免出现重复序列,
                    // 需要忽略一个数;
                    // 那为什么是dp[i]?事实上任意一个都可以,是哪个不都一样吗?并不影响序列后面的方案数
                    // 如果不是dp[i] == 1的情况(也就是虽然数字重复,但已经参与到了新的不重复的序列中),
                    // 由于要保存中间状态,就不能置为0,直接跳过就好
                    if(dp[i] == 1){
                        project[i] = 0;
                    }
                    break;
                }
            }
        }
        // 计算maxdp和maxLen
        int maxDp = 0;
        int maxLen = 0;
        for (int i = 1; i <= n; ++i)
        {
            if(maxDp < dp[i])
                maxDp = dp[i];
        }
        for (int i = 1; i <= n; ++i)
        {
            if(maxDp == dp[i])
                maxLen += project[i];
        }
        printf("%d %d\n", maxDp, maxLen);
    }
    return 0;
}

我说我看这道题看了一星期,你会信吗-_-

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值