#P1480. 第1题-小红的好数组对
-
1000ms
Tried: 146
Accepted: 25
Difficulty: 6
所属公司 :
拼多多
时间 :2023年8月22日
-
算法标签>动态规划
第1题-小红的好数组对
思路:动态规划
状态定义:
考虑 val[i][0] 表示只考虑前 i 个数,第 i 个数,ai 与 bi 不交换的情况下,可以获得的相邻数的差值绝对值之和的最大值。
考虑 val[i][1] 表示只考虑前 i 个数,第 i 个数,ai 与 bi 交换的情况下,可以获得的相邻数的差值绝对值之和的最大值。
状态转移:
$val[i][0]=\max(val[i - 1][0] + abs(a[i] - a[i - 1]) + abs(b[i] - b[i - 1]), val[i - 1][1] + abs(a[i] - b[i - 1]) + abs(b[i] - a[i - 1]))$
$val[i][1]=\max(val[i - 1][0] + abs(b[i] - a[i - 1]) + abs(a[i] - b[i - 1]), val[i - 1][1] + abs(a[i] - a[i - 1]) + abs(b[i] - b[i - 1]))$
此外,我们还需要记录每个状态需要交换的次数。
cnt[i][0], 表示只考虑前 i 个数,第 i 个数,ai 与 bi 不交换的情况下,在获得 val[i][0] 的情况下,需要的最少交换次数。
cnt[i][1], 表示只考虑前 i 个数,第 i 个数,ai 与 bi 交换的情况下,在获得 val[i][1] 的情况下,需要的最少交换次数。
最后答案为,max(val[n−1][0],val[n−1][1]) 对应的 cnt[n−1] ,如果两者 val[n−1][0]=val[n−1][1] ,则取 min(cnt[n−1]) 即可。
时间复杂度:O(n)
代码
C++
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 100010;
int a[N], b[N];
ll val[N][2];
ll cnt[N][2];
void solve() {
int n;
cin >> n;
for (int i = 0; i < n; ++i) cin >> a[i];
for (int i = 0; i < n; ++i) cin >> b[i];
// val[i][0] 表示不交换 ai, bi
// val[i][1] 表示交换 ai, bi
val[0][0] = val[0][1] = 0;
cnt[0][0] = 0, cnt[0][1] = 1;
for (int i = 1; i < n; ++i) {
val[i][0] = val[i - 1][0] + abs(a[i] - a[i - 1]) + abs(b[i] - b[i - 1]);
cnt[i][0] = cnt[i - 1][0];
if (val[i - 1][1] + abs(a[i] - b[i - 1]) + abs(b[i] - a[i - 1]) > val[i][0]) {
val[i][0] = val[i - 1][1] + abs(a[i] - b[i - 1]) + abs(b[i] - a[i - 1]);
cnt[i][0] = cnt[i - 1][1];
} else if (val[i - 1][1] + abs(a[i] - b[i - 1]) + abs(b[i] - a[i - 1]) == val[i][0] && cnt[i - 1][1] < cnt[i][0]) {
cnt[i][0] = min(cnt[i][0], cnt[i - 1][1]);
}
val[i][1] = val[i - 1][0] + abs(b[i] - a[i - 1]) + abs(a[i] - b[i - 1]);
cnt[i][1] = cnt[i - 1][0] + 1;
if (val[i - 1][1] + abs(a[i] - a[i - 1]) + abs(b[i] - b[i - 1]) > val[i][1]) {
val[i][1] = val[i - 1][1] + abs(a[i] - a[i - 1]) + abs(b[i] - b[i - 1]);
cnt[i][1] = cnt[i - 1][1] + 1;
} else if (val[i - 1][1] + abs(a[i] - a[i - 1]) + abs(b[i] - b[i - 1]) == val[i][1]) {
cnt[i][1] = min(cnt[i][1], cnt[i - 1][1] + 1);
}
}
if (val[n - 1][0] > val[n - 1][1]) {
cout << cnt[n - 1][0] << "\n";
} else if (val[n - 1][0] < val[n - 1][1]) {
cout << cnt[n - 1][1] << "\n";
} else {
cout << min(cnt[n - 1][0], cnt[n - 1][1]) << "\n";
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin >> T;
while (T--) solve();
return 0;
}
python
def solve():
n = int(input())
a = list(map(int, input().split()))
b = list(map(int, input().split()))
val = [[0, 0] for _ in range(n)]
cnt = [[0, 0] for _ in range(n)]
val[0][0] = val[0][1] = 0
cnt[0][0] = 0
cnt[0][1] = 1
for i in range(1, n):
val[i][0] = val[i - 1][0] + abs(a[i] - a[i - 1]) + abs(b[i] - b[i - 1])
cnt[i][0] = cnt[i - 1][0]
if val[i - 1][1] + abs(a[i] - b[i - 1]) + abs(b[i] - a[i - 1]) > val[i][0]:
val[i][0] = val[i - 1][1] + abs(a[i] - b[i - 1]) + abs(b[i] - a[i - 1])
cnt[i][0] = cnt[i - 1][1]
elif val[i - 1][1] + abs(a[i] - b[i - 1]) + abs(b[i] - a[i - 1]) == val[i][0] and cnt[i - 1][1] < cnt[i][0]:
cnt[i][0] = min(cnt[i][0], cnt[i - 1][1])
val[i][1] = val[i - 1][0] + abs(b[i] - a[i - 1]) + abs(a[i] - b[i - 1])
cnt[i][1] = cnt[i - 1][0] + 1
if val[i - 1][1] + abs(a[i] - a[i - 1]) + abs(b[i] - b[i - 1]) > val[i][1]:
val[i][1] = val[i - 1][1] + abs(a[i] - a[i - 1]) + abs(b[i] - b[i - 1])
cnt[i][1] = cnt[i - 1][1] + 1
elif val[i - 1][1] + abs(a[i] - a[i - 1]) + abs(b[i] - b[i - 1]) == val[i][1]:
cnt[i][1] = min(cnt[i][1], cnt[i - 1][1] + 1)
if val[n - 1][0] > val[n - 1][1]:
print(cnt[n - 1][0])
elif val[n - 1][0] < val[n - 1][1]:
print(cnt[n - 1][1])
else:
print(min(cnt[n - 1][0], cnt[n - 1][1]))
T = int(input())
for _ in range(T):
solve()
Java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int T = Integer.parseInt(br.readLine());
for (int t = 0; t < T; t++) {
solve(br);
}
}
static void solve(BufferedReader br) throws IOException {
int n = Integer.parseInt(br.readLine());
int[] a = new int[n];
int[] b = new int[n];
StringTokenizer st = new StringTokenizer(br.readLine());
for (int i = 0; i < n; i++) {
a[i] = Integer.parseInt(st.nextToken());
}
st = new StringTokenizer(br.readLine());
for (int i = 0; i < n; i++) {
b[i] = Integer.parseInt(st.nextToken());
}
long[][] val = new long[n][2];
long[][] cnt = new long[n][2];
val[0][0] = val[0][1] = 0;
cnt[0][0] = 0;
cnt[0][1] = 1;
for (int i = 1; i < n; i++) {
val[i][0] = val[i - 1][0] + Math.abs(a[i] - a[i - 1]) + Math.abs(b[i] - b[i - 1]);
cnt[i][0] = cnt[i - 1][0];
if (val[i - 1][1] + Math.abs(a[i] - b[i - 1]) + Math.abs(b[i] - a[i - 1]) > val[i][0]) {
val[i][0] = val[i - 1][1] + Math.abs(a[i] - b[i - 1]) + Math.abs(b[i] - a[i - 1]);
cnt[i][0] = cnt[i - 1][1];
} else if (val[i - 1][1] + Math.abs(a[i] - b[i - 1]) + Math.abs(b[i] - a[i - 1]) == val[i][0] && cnt[i - 1][1] < cnt[i][0]) {
cnt[i][0] = Math.min(cnt[i][0], cnt[i - 1][1]);
}
val[i][1] = val[i - 1][0] + Math.abs(b[i] - a[i - 1]) + Math.abs(a[i] - b[i - 1]);
cnt[i][1] = cnt[i - 1][0] + 1;
if (val[i - 1][1] + Math.abs(a[i] - a[i - 1]) + Math.abs(b[i] - b[i - 1]) > val[i][1]) {
val[i][1] = val[i - 1][1] + Math.abs(a[i] - a[i - 1]) + Math.abs(b[i] - b[i - 1]);
cnt[i][1] = cnt[i - 1][1] + 1;
} else if (val[i - 1][1] + Math.abs(a[i] - a[i - 1]) + Math.abs(b[i] - b[i - 1]) == val[i][1]) {
cnt[i][1] = Math.min(cnt[i][1], cnt[i - 1][1] + 1);
}
}
if (val[n - 1][0] > val[n - 1][1]) {
System.out.println(cnt[n - 1][0]);
} else if (val[n - 1][0] < val[n - 1][1]) {
System.out.println(cnt[n - 1][1]);
} else {
System.out.println(Math.min(cnt[n - 1][0], cnt[n - 1][1]));
}
}
}
题目内容
小红有两个长度均为 n 数组 a 和 b 。
对于这两个数组,当这两个数组满足 $(\sum\limits_{i=2}^n |a_i-a_{i-1}|) + (\sum\limits_{i=2}^n |b_i-b_{i-1}|)$ 的和最大时,称这两个数组是一个好数组对。
小红允许你交换数组 a 和数组 b 中的任意两个对应位置的元素 ai 和 bi 。
现在,小红想问你,最少要交换多少次可以使得这两个数组成为一个好数组对。
输入描述
第一行,一个整数 T(1≤T≤10) ,表示数据组数。 接下来每组数据,
第一行,一个整数 n(2≤n≤105) 表示数组大小。
第二行,n 个整数,表示数组 a 的 n 个数,1≤ai≤109。
第三行,n 个整数,表示数组 b 的 n 个数,1≤bi≤109。
保证 T 组数据所有 n 的和不超过 105
输出描述
一个整数
样例
输入
1
2
1 2
4 5
输出
1
说明
交换 a2 和 b2 。
得到 a = [1, 5], b = [4, 2]
总和为 6 ,其余任何方案都不会使得答案大于 6