【LIS】HDU - 1003 Max Sum 简单易懂的讲解

这篇博客详细讲解了如何使用动态规划解决HDU 1003 Max Sum问题。通过动态规划数组dp[i]记录到位置i的最大子序列和,根据dp[i-1]的值判断是否包含当前元素a[i],并给出两种情况的策略:当dp[i-1]<0时,dp[i]=a[i];当dp[i-1]>=0时,dp[i]=dp[i-1]+a[i]。博主提供了参考代码来辅助理解。

HDU - 1003 Max Sum

解题思路

动态规划, d p [ i ] dp[i] dp[i] 记录到位置 i i i 的最大子序列和。

判断过程中,有两种情况:

  • d p [ i − 1 ] < 0 dp[i - 1] < 0 dp[i1]<0 :可以这么理解,前面的最大和都是负数了, 我 a [ i ] a[i] a[i] 为什么还要去瞎掺和?

    我如果是负数,加进去肯定使得 d p [ i ] dp[i] dp[i] 更小了,不划算;我如果是正数,加进去也不划算,相当于莫名其妙被减了一点,还不如另辟蹊径重新开始算。因此这种情况,采取策略: d p [ i ] = a [ i ] dp[i] = a[i] dp[i]=a[i]

  • d p [ i − 1 ] > = 0 dp[i - 1] >= 0 dp[i1]>=0:那就正常算,因为 d p [ i ] dp[i] dp[i] 表示的是到当前位置的最大和,那么 a [ i ] a[i] a[i] 总归是要算进来的,即 d p [ i ] = d p [ i − 1 ] + a [ i ] dp[i] = dp[i - 1] + a[i] dp[i]=dp[i1]+a[i]

遍历的过程中,更新答案即可。

参考代码

#include<stdio.h>
#include<iostream>
#include<vector>
#include<cstring>
#include<cstdio>
#include<climits>
#include<cmath>
#include<algorithm>
#include<queue>
#include<deque>
#include<map>
#include<set>
#include<stack>
//#define LOCAL  //提交时一定注释
#define VI vector<int>
typedef long long LL;
typedef double db;
const int inf = 0x3f3f3f3f;
const LL INF = 1e18;
const int N = 1e3 + 10;
using namespace std;
const int mod = 1e9 + 7;
const int M = 1e5 + 10;
const int base = 400;
int readint() {int x; scanf("%d", &x); return x;}

int dp[M], a[M];

void init() {
    dp[0] = -1;  //这个是方便后面写代码,dp[1]就不用特殊处理了
}

int main() {
#ifdef LOCAL
    freopen("input.txt", "r", stdin);
//   freopen("output.txt", "w", stdout);
#endif
    int t = readint();
    for(int ca = 1; ca <= t; ca++) {
        init();
        int n = readint();
        for(int i = 1; i <= n; i++)
            a[i] = readint();
        int ans = -inf, s, e, ansl, ansr;
        for(int i = 1; i <= n; i++) {
            if (dp[i - 1] < 0) {  //另辟蹊径
                dp[i] = a[i];
                s = e = i;  //更新开始、结束的位置
            }
            else {
                dp[i] = dp[i - 1] + a[i];
                e = i;
            }
            if (dp[i] > ans) {  //更新答案
                ans = dp[i];
                ansl = s, ansr = e;
            }
        }
        if (ca > 1) printf("\n");
        printf("Case %d:\n", ca);
        printf("%d %d %d\n", ans, ansl, ansr);
    }

    return 0;
}

<think> 我们被要求解释代码`print(lis[-1:])`的作用。 根据Python的切片规则: - 切片操作`list[start:end]`用于获取列表从索引`start`到`end-1`的元素。 - 当使用负数索引时,表示从列表的末尾开始计数,例如`-1`表示最后一个元素,`-2`表示倒数第二个,以此类推。 - 在`lis[-1:]`中: start = -1 # 表示最后一个元素的索引 end 不指定,但实际上切片操作中如果省略第二个参数,则表示到列表结束。 但是,需要注意的是,`lis[-1:]`实际上表示从索引为-1(即最后一个元素)一直到列表的末尾。由于在列表中最后一个元素之后已经没有元素,所以这个切片的结果就是包含原列表最后一个元素的列表(注意:是列表,而不是单个元素)。 例如: lis = [1, 2, 3, 4] lis[-1:] 的结果是 [4] # 注意这是一个包含单个元素4的列表 对比: lis[-1] 得到的是元素4(整数4),而lis[-1:]得到的是[4](列表)。 因此,`print(lis[-1:])`的作用是:打印原列表`lis`的最后一个元素组成的列表。 示例: >>> lis = [10, 20, 30] >>> print(lis[-1:]) [30] 注意:如果列表为空,那么这个切片不会引发错误,而是返回一个空列表。 >>> lis = [] >>> print(lis[-1:]) [] 另外,引用中提到了关于列表的一些操作,但并没有直接与这个问题相关的。不过,我们可以参考引用[1]中的切片示例:`lis[::2]`,这是一个步长为2的切片。而我们的问题是一个简单的单元素切片。 因此,总结如下: `print(lis[-1:])` 的作用是打印列表`lis`中最后一个元素组成的子列表(即只包含最后一个元素的列表)。如果列表为空,则打印空列表。 在回答中,我们还可以生成相关问题,以帮助用户深入理解。 </think> ### Python代码 `print(lis[-1:])` 的作用详解 `print(lis[-1:])` 是Python中列表切片操作的特殊用法,主要用于**获取列表的最后一个元素并以列表形式输出**。具体解析如下: #### 1. **核心机制** - **负索引**:Python允许使用负数索引,`-1` 表示列表的最后一个元素 - **切片语法**:`list[start:end]` - `lis[-1:]` 表示从索引 `-1`(最后一个元素)开始,到列表结束 - 由于结束位置未指定(省略 `end` 参数),默认截取到列表末尾 - **返回值**:始终返回**包含目标元素的子列表**(即使只有一个元素) #### 2. **与直接索引 `lis[-1]` 的区别** | 操作 | 返回值类型 | 空列表处理 | 示例 (`lis=[10,20,30]`) | |---------------|------------|----------------|--------------------------| | `print(lis[-1:])` | 列表 | 返回 `[]` | 输出: `[30]` | | `print(lis[-1])` | 元素本身 | 引发 `IndexError` | 输出: `30` | #### 3. **典型使用场景** ```python # 场景1:安全获取最后元素(避免空列表报错) scores = [88, 92, 78] last_score = scores[-1:] # 安全:即使scores=[]也返回[] # 场景2:保持结果一致性(需要列表类型) data = [[1,2], [3,4]] last_row = data[-1:] # 返回 [[3,4]] 而非 [3,4] # 场景3:链式切片操作 text = "Python切片" last_char = text[-1:] # 返回 ['片'],可直接用于 ''.join() ``` #### 4. **特殊边界情况处理** ```python # 空列表返回空列表 print([][-1:]) # 输出: [] # 单元素列表返回单元素列表 print(["A"][-1:]) # 输出: ['A'] # 嵌套列表保持结构 matrix = [[1,2], [3,4]] print(matrix[-1:]) # 输出: [[3,4]] ``` #### 5. **底层实现原理** 该操作等同于: ```python if len(lis) > 0: return [lis[-1]] # 将最后一个元素包装为新列表 else: return [] # 空列表直接返回 ``` 其时间复杂度为 $O(1)$,因为只是创建新列表的引用而非复制元素[^1]。 #### 6. **实用技巧延伸** ```python # 获取最后N个元素:使用 lis[-N:] print([10,20,30,40][-2:]) # 输出: [30,40] # 结合其他切片参数 print([1,2,3,4,5][-3::2]) # 从倒数第3元素开始,步长2 → [3,5] ``` ### 常见误区 1. **误解为获取单个元素**:实际上返回的是单元素列表 2. **混淆负数索引方向**:`-1` 是最后一个,`-2` 是倒数第二个 3. **忽略空列表安全性**:这是比直接索引更安全的写法[^2] --- ### 相关问题 1. 如何用切片操作获取列表的**前N个元素**? 2. `lis[-0:]` 会返回什么结果?为什么? 3. 在循环中直接删除 `lis[-1:]` 的元素是否安全? 4. 如何高效实现队列的**pop_last**功能? 5. 字符串切片 `"hello"[-2:]` 的结果是什么?[^3]
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值