时间序列
题目分析
给定两个序列 A(长度 n)和 B(长度 m),分别从 A 和 B 中选出等长的非空子序列(保持元素在原序列中的相对顺序),定义"共振度"为对应位置元素之差的绝对值之和。求最大共振度。
思路
动态规划(LCS 变种)
本题是经典最长公共子序列(LCS)的变种。LCS 是求最长匹配,而本题是求最大代价匹配——每匹配一对 ,贡献
,目标是最大化总贡献。
定义 为只考虑 A 的前
个元素和 B 的前
个元素时,能获得的最大共振度。转移方程:
$$
初始值 ,答案为
。
这与 LCS 的转移结构完全一致,只是把"长度+1"替换为"累加绝对值差"。由于每一行只依赖上一行,可以用滚动数组将空间优化到 。
以样例 1 为例验证: A=[1,3,5], B=[2,4,6]。选择子序列 A'=[1,3], B'=[4,6],共振度 ,即为最大值。
代码
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, m;
scanf("%d%d", &n, &m);
vector<int> a(n), b(m);
for (int i = 0; i < n; i++) scanf("%d", &a[i]);
for (int i = 0; i < m; i++) scanf("%d", &b[i]);
vector<long long> dp(m + 1, 0);
for (int i = 0; i < n; i++) {
vector<long long> ndp(m + 1, 0);
for (int j = 1; j <= m; j++) {
ndp[j] = max({ndp[j - 1], dp[j],
dp[j - 1] + (long long)abs(a[i] - b[j - 1])});
}
dp = ndp;
}
printf("%lld\n", dp[m]);
return 0;
}
import java.util.*;
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StreamTokenizer in = new StreamTokenizer(br);
in.nextToken(); int n = (int) in.nval;
in.nextToken(); int m = (int) in.nval;
int[] a = new int[n], b = new int[m];
for (int i = 0; i < n; i++) { in.nextToken(); a[i] = (int) in.nval; }
for (int i = 0; i < m; i++) { in.nextToken(); b[i] = (int) in.nval; }
long[] dp = new long[m + 1];
for (int i = 0; i < n; i++) {
long[] ndp = new long[m + 1];
for (int j = 1; j <= m; j++) {
ndp[j] = Math.max(Math.max(ndp[j - 1], dp[j]),
dp[j - 1] + Math.abs(a[i] - b[j - 1]));
}
dp = ndp;
}
System.out.println(dp[m]);
}
}
import sys
input = sys.stdin.readline
def main():
n, m = map(int, input().split())
a = list(map(int, input().split()))
b = list(map(int, input().split()))
dp = [0] * (m + 1)
for i in range(n):
ndp = [0] * (m + 1)
for j in range(1, m + 1):
ndp[j] = max(ndp[j - 1], dp[j], dp[j - 1] + abs(a[i] - b[j - 1]))
dp = ndp
print(dp[m])
main()
const readline = require('readline');
const rl = readline.createInterface({ input: process.stdin });
const lines = [];
rl.on('line', line => lines.push(line.trim()));
rl.on('close', () => {
const [n, m] = lines[0].split(' ').map(Number);
const a = lines[1].split(' ').map(Number);
const b = lines[2].split(' ').map(Number);
let dp = new Array(m + 1).fill(0);
for (let i = 0; i < n; i++) {
const ndp = new Array(m + 1).fill(0);
for (let j = 1; j <= m; j++) {
ndp[j] = Math.max(ndp[j - 1], dp[j],
dp[j - 1] + Math.abs(a[i] - b[j - 1]));
}
dp = ndp;
}
console.log(dp[m]);
});
复杂度分析
- 时间复杂度:
,双重循环遍历两个序列。
- 空间复杂度:
,滚动数组优化后只需一维数组。

京公网安备 11010502036488号