#P3714. 第1题-最大化安全评分
          
                        
                                    
                      
        
              - 
          
          
                      1000ms
            
          
                      Tried: 660
            Accepted: 182
            Difficulty: 6
            
          
          
          
                       所属公司 : 
                              华为
                                
            
                        
              时间 :2025年9月17日-非AI方向(通软&嵌软&测试&算法&数据科学)
                              
                      
          
 
- 
                        算法标签>动态规划          
 
第1题-最大化安全评分
题面描述
安全分析师小王正在开发一款先进的入侵检测系统(IDS),旨在实时监控网络流量并识别潜在的恶意活动。系统将网络抽象为一个下标从0开始的整数数组 node_scores,其中每个元素代表对应位置的安全评分:正值表示安全或有正面安全措施,负值表示存在潜在风险或威胁。 分析师从入口节点(下标0)开始,每一步最多可以前进K步,但不能超出数组边界。也就是说,如果当前位于下标i,则可以跳到任意下标j,满足
i+1≤j≤min(n−1,i+K)
目标是到达下标n−1(最后一个监控点),并使累积的安全评分总和最大。注意:路径上的评分可能为正也可能为负。
思路
- 
记dp[i]为到达节点i时的最大累积安全得分,则期望: dp[i] =maxj∈[i−K,i−1](dp[j]) +node_scores[i].
 - 
直接计算会导致每个i遍历K个前驱,整体时间O(nK),在n,K均可达105 时不可行。
 - 
使用「单调队列」优化滑动窗口最大值的维护:维护一个双端队列
dq,其中保存候选下标,并保持对应的dp值递减。- 维护队首始终是窗口内最大的dp下标;
 - 当处理到i时,将不在窗口 [i−K,i−1] 的下标从队首或队尾剔除;
 - 利用队首的dp值计算 dp[i],再将i插入队列时,从队尾剔除所有dp值不大于 dp[i]的下标,保证队列单调递减。
 
 - 
这样每个元素进出队列各一次,整体时间O(n),空间O(n)。
 
C++
#include <bits/stdc++.h>
using namespace std;
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int K, n;
    cin >> K >> n;
    vector<int> node_scores(n);
    for (int i = 0; i < n; i++) {
        cin >> node_scores[i];
    }
    // dp[i] 表示到达节点 i 时的最大安全得分
    vector<long long> dp(n, LLONG_MIN);
    dp[0] = node_scores[0];
    deque<int> dq;
    dq.push_back(0);  // 双端队列中存放下标,并保持 dp[dq] 递减
    for (int i = 1; i < n; i++) {
        // 剔除队首中不在窗口 [i-K, i-1] 的下标
        while (!dq.empty() && dq.front() < i - K) {
            dq.pop_front();
        }
        // 当前 dp 转移:使用窗口最大值 + 当前节点分数
        dp[i] = dp[dq.front()] + node_scores[i];
        // 插入 i,保持队列单调递减
        while (!dq.empty() && dp[dq.back()] <= dp[i]) {
            dq.pop_back();
        }
        dq.push_back(i);
    }
    cout << dp[n-1] << "\n";
    return 0;
}
Python
import sys
from collections import deque
def max_score(node_scores, K):
    n = len(node_scores)
    dp = [-10**18] * n  # 初始化为足够小的值
    dp[0] = node_scores[0]
    dq = deque([0])  # 存放下标,维护 dp 递减
    for i in range(1, n):
        # 移除过期的窗口左侧下标
        while dq and dq[0] < i - K:
            dq.popleft()
        # 转移方程
        dp[i] = dp[dq[0]] + node_scores[i]
        # 维护单调队列
        while dq and dp[dq[-1]] <= dp[i]:
            dq.pop()
        dq.append(i)
    return dp[-1]
if __name__ == "__main__":
    data = sys.stdin.read().split()
    K = int(data[0])
    n = int(data[1])
    scores = list(map(int, data[2:2+n]))
    print(max_score(scores, K))
Java
import java.io.*;
import java.util.*;
public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int K = Integer.parseInt(br.readLine().trim());
        int n = Integer.parseInt(br.readLine().trim());
        StringTokenizer st = new StringTokenizer(br.readLine());
        
        long[] dp = new long[n];
        int[] nodeScores = new int[n];
        for (int i = 0; i < n; i++) {
            nodeScores[i] = Integer.parseInt(st.nextToken());
        }
        // 初始化 dp 数组
        Arrays.fill(dp, Long.MIN_VALUE);
        dp[0] = nodeScores[0];
        Deque<Integer> dq = new ArrayDeque<>();
        dq.addLast(0);  // 存放下标,dp 递减
        for (int i = 1; i < n; i++) {
            // 移除窗口外的下标
            while (!dq.isEmpty() && dq.peekFirst() < i - K) {
                dq.pollFirst();
            }
            // 状态转移
            dp[i] = dp[dq.peekFirst()] + nodeScores[i];
            // 维护单调队列
            while (!dq.isEmpty() && dp[dq.peekLast()] <= dp[i]) {
                dq.pollLast();
            }
            dq.addLast(i);
        }
        System.out.println(dp[n-1]);
    }
}
        题目内容
安全分析师小王正在开发一款先进的入侵检测系统 (IDS),旨在实时监控网络流量并失败潜在的恶意活动;如何在一个复杂的网络环境中,从起始节点出发,到达终端节点(即最后一个监控点),同时最大化累积的安全评分。
在这个系统中,整个网络被抽象为一个下标从 0 开始的整数数组 node _scores ,其中每个元素代表对应位置的安全评分。正值表示该位置是安全的或有正面的安全措施,而负值则表示存在潜在风险或威胁。分析师开始于位置 0 (入口节点),每一步可以前进最多 k 步,但不能超出数组边界。也就是说,如果当前位于下标 i ,则可以选择跳到 [i+1,min(n−1,i+k)] 包含两个端点的任意位置。目标是到达数组的最后一个位置(即最后一个监控点,下标为 n−1 ),并且在此过程中最大化累积的安全评分得分。这里的得分可以是正也可以是负,取决于路径上遇到的安全状况。
具体任务是编写一个算法,给定一个整数数组 node _scores 和一个整数 k ,该算法应返回能够获得的最大得分。这个得分是通过选将一条从起点到终点的最佳路径来实现的,这条路径上的所有数字之和即为最大得分,即使某些位置的安全评分为负。
输入描述
每组数据第一行为最大的进步数 k ,第二行为节点数量 n ,第三行的 n 个数为每个节点的安全得分
输入范围限制:
- 
1<=node _scores.length,k<=100000
 - 
−10000<=node _scores[i]<=10000
 
输出描述
到达最后一个节点时可以获得的最大安全得分
样例1
输入
2
8
3 -5 -10 2 -1 5 -6 -5
输出
0
说明
最多可前进步数 k=2 ,安全评分数组长度 n=8 ,数组 nodes _cores 的具体值为 =[3,−5,−10,2,−1,5,−6,−5] ,可使安全评分最大的子字列 [3,−5,2,5,−5] ,因此最大安全得到为 0
样例2
输入
3
6
1 -5 -2 4 0 7
输出
12
说明
最多可前进步数 k=3 ,安全评分数组长度 n=6 ,数组 nodes _cores 的具体值为 =[1,−5,−2,4,0,7] ,可使安全评分最大的子字列 [1,4,7] ,因此最大安全得到为 12
样例3
输入
2
6
1 -3 -2 4 -7 5
输出
8
说明
最多可前进步数 k=2 ,安全评分数组长度 n=6 ,数组 nodes _cores 的具体值为 =[1,−3,−2,4,−7,5] ,可使安全评分最大的子字列 [1,−2,4,5] ,因此最大安全得到为 8