题目链接
题目描述
在基于 RAG(检索增强生成)的问答系统中,知识库需要定期更新以保持有效性。
- 在接下来的
个连续自然日内,给定每日的更新成本
和查询收益
。
- 初始状态下,知识库是“过期”的。
- 若在第
天执行更新,则知识库从第
天起连续
天处于“有效”状态(覆盖区间
),期间可以获得查询收益。
- 每天可以从以下三种操作中选择一个:
- 更新并查询:支付
,若当日有效则获得
。
- 仅查询:若当日处于有效期内,获得
;否则收益为 0。
- 什么也不做:无成本无收益。
- 更新并查询:支付
- 目标:计算
天内能获得的最大净利润(总收益
总成本)。
输入描述:
- 第一行:
。
- 第二行:
个整数,代表
。
- 第三行:
个整数,代表
。
输出描述:
- 一个整数,代表最大净利润。
解题思路
这是一个带有时间窗口约束的动态规划问题,可以通过单调队列进行优化。
-
状态定义: 设
表示前
天(即日期
)能获得的最大净利润。
-
状态转移: 对于第
天(对应的索引为
):
- 如果第
天不进行有效的查询(即不处于任何更新周期,或主动放弃),则
。
- 如果第
天处于某个更新周期内,假设该周期的起始更新日为
(
),则该周期从
到
的总收益为
。
- 转移方程:
。
- 如果第
-
优化: 引入前缀和
。 则
。 转移方程变为:
。 令
,该项仅与
相关。我们可以使用单调队列维护滑动窗口
内
的最大值。
-
复杂度:
- 每个元素入队和出队各一次,时间复杂度为
。
- 空间复杂度为
,用于存储数组和单调队列。
- 每个元素入队和出队各一次,时间复杂度为
代码
#include <iostream>
#include <vector>
#include <deque>
#include <algorithm>
using namespace std;
typedef long long LL;
int main() {
int n, d;
cin >> n >> d;
vector<LL> cost(n), reward(n);
for (int i = 0; i < n; ++i) cin >> cost[i];
for (int i = 0; i < n; ++i) cin >> reward[i];
vector<LL> P(n + 1, 0);
for (int i = 0; i < n; ++i) P[i + 1] = P[i] + reward[i];
vector<LL> dp(n + 1, 0);
vector<LL> V(n);
deque<int> dq;
for (int i = 1; i <= n; ++i) {
int j = i - 1;
V[j] = dp[j] - cost[j] - P[j];
while (!dq.empty() && V[j] >= V[dq.back()]) {
dq.pop_back();
}
dq.push_back(j);
if (dq.front() < i - d) {
dq.pop_front();
}
dp[i] = max(dp[i - 1], P[i] + V[dq.front()]);
}
cout << dp[n] << endl;
return 0;
}
import java.util.Scanner;
import java.util.ArrayDeque;
import java.util.Deque;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int d = sc.nextInt();
long[] cost = new long[n];
long[] reward = new long[n];
for (int i = 0; i < n; i++) cost[i] = sc.nextLong();
for (int i = 0; i < n; i++) reward[i] = sc.nextLong();
long[] P = new long[n + 1];
for (int i = 0; i < n; i++) P[i + 1] = P[i] + reward[i];
long[] dp = new long[n + 1];
long[] V = new long[n];
Deque<Integer> dq = new ArrayDeque<>();
for (int i = 1; i <= n; i++) {
int j = i - 1;
V[j] = dp[j] - cost[j] - P[j];
while (!dq.isEmpty() && V[j] >= V[dq.peekLast()]) {
dq.pollLast();
}
dq.offerLast(j);
if (dq.peekFirst() < i - d) {
dq.pollFirst();
}
dp[i] = Math.max(dp[i - 1], P[i] + V[dq.peekFirst()]);
}
System.out.println(dp[n]);
}
}
from collections import deque
def solve():
n, d = map(int, input().split())
costs = list(map(int, input().split()))
rewards = list(map(int, input().split()))
p_sum = [0] * (n + 1)
for i in range(n):
p_sum[i + 1] = p_sum[i] + rewards[i]
dp = [0] * (n + 1)
v_vals = [0] * n
dq = deque()
for i in range(1, n + 1):
j = i - 1
v_vals[j] = dp[j] - costs[j] - p_sum[j]
while dq and v_vals[j] >= v_vals[dq[-1]]:
dq.pop()
dq.append(j)
if dq[0] < i - d:
dq.popleft()
# dp[i] 可以是不查询,或者在这个窗口内更新
dp[i] = max(dp[i - 1], p_sum[i] + v_vals[dq[0]])
print(dp[n])
if __name__ == "__main__":
solve()
算法及复杂度
- 算法:动态规划
单调队列优化。
- 时间复杂度:
。通过前缀和与单调队列将转移时间从
优化至
,总复杂度与天数
成线性关系。
- 空间复杂度:
。需要存储成本、收益、前缀和、状态及单调队列。

京公网安备 11010502036488号