为了更好的阅读体检,可以查看我的算法学习网
在线评测链接:P1480
视频题解
题目内容
塔子哥有两个长度均为 n n n 数组 a a a 和 b b b 。
对于这两个数组,当这两个数组满足 ( ∑ i = 2 n ∣ a i − a i − 1 ∣ ) + ( ∑ i = 2 n ∣ b i − b i − 1 ∣ ) (\sum\limits_{i=2}^n |a_i-a_{i-1}|) + (\sum\limits_{i=2}^n |b_i-b_{i-1}|) (i=2∑n∣ai−ai−1∣)+(i=2∑n∣bi−bi−1∣) 的和最大时,称这两个数组是一个好数组对。
塔子哥允许你交换数组 a a a 和数组 b b b 中的任意两个对应位置的元素 a i a_i ai 和 b i b_i bi 。
现在,塔子哥想问你,最少要交换多少次可以使得这两个数组成为一个好数组对。
输入描述
第一行,一个整数
T
(
1
≤
T
≤
10
)
T(1\leq T\leq 10)
T(1≤T≤10) ,表示数据组数。
接下来每组数据,
第一行,一个整数 n ( 2 ≤ n ≤ 1 0 5 ) n(2\leq n\leq 10^5) n(2≤n≤105) 表示数组大小。
第二行, n n n 个整数,表示数组 a a a 的 n n n 个数, 1 ≤ a i ≤ 1 0 9 1\leq a_i\leq 10^9 1≤ai≤109。
第三行, n n n 个整数,表示数组 b b b 的 n n n 个数, 1 ≤ b i ≤ 1 0 9 1\leq b_i\leq 10^9 1≤bi≤109。
保证 T T T 组数据所有 n n n 的和不超过 1 0 5 10^5 105
输出描述
一个整数
样例
输入
1
2
1 2
4 5
输出
1
说明
交换
a
2
a_2
a2 和
b
2
b_2
b2 。
得到 a = [1, 5], b = [4, 2]
总和为
6
6
6 ,其余任何方案都不会使得答案大于
6
6
6
思路:动态规划
状态定义:
考虑
v
a
l
[
i
]
[
0
]
val[i][0]
val[i][0] 表示只考虑前
i
i
i 个数,第
i
i
i 个数,
a
i
a_i
ai 与
b
i
b_i
bi 不交换的情况下,可以获得的相邻数的差值绝对值之和的最大值。
考虑
v
a
l
[
i
]
[
1
]
val[i][1]
val[i][1] 表示只考虑前
i
i
i 个数,第
i
i
i 个数,
a
i
a_i
ai 与
b
i
b_i
bi 交换的情况下,可以获得的相邻数的差值绝对值之和的最大值。
状态转移:
v a l [ i ] [ 0 ] = max ( v a l [ i − 1 ] [ 0 ] + a b s ( a [ i ] − a [ i − 1 ] ) + a b s ( b [ i ] − b [ i − 1 ] ) , v a l [ i − 1 ] [ 1 ] + a b s ( a [ i ] − b [ i − 1 ] ) + a b s ( b [ i ] − a [ i − 1 ] ) ) 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][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]))
v a l [ i ] [ 1 ] = max ( v a l [ i − 1 ] [ 0 ] + a b s ( b [ i ] − a [ i − 1 ] ) + a b s ( a [ i ] − b [ i − 1 ] ) , v a l [ i − 1 ] [ 1 ] + a b s ( a [ i ] − a [ i − 1 ] ) + a b s ( b [ i ] − b [ 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])) 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]))
此外,我们还需要记录每个状态需要交换的次数。
c n t [ i ] [ 0 ] cnt[i][0] cnt[i][0], 表示只考虑前 i i i 个数,第 i i i 个数, a i a_i ai 与 b i b_i bi 不交换的情况下,在获得 v a l [ i ] [ 0 ] val[i][0] val[i][0] 的情况下,需要的最少交换次数。
c n t [ i ] [ 1 ] cnt[i][1] cnt[i][1], 表示只考虑前 i i i 个数,第 i i i 个数, a i a_i ai 与 b i b_i bi 交换的情况下,在获得 v a l [ i ] [ 1 ] val[i][1] val[i][1] 的情况下,需要的最少交换次数。
最后答案为, max ( v a l [ n − 1 ] [ 0 ] , v a l [ n − 1 ] [ 1 ] ) \max(val[n-1][0], val[n-1][1]) max(val[n−1][0],val[n−1][1]) 对应的 c n t [ n − 1 ] cnt[n-1] cnt[n−1] ,如果两者 v a l [ n − 1 ] [ 0 ] = v a l [ n − 1 ] [ 1 ] val[n-1][0]=val[n-1][1] val[n−1][0]=val[n−1][1] ,则取 min ( c n t [ n − 1 ] ) \min(cnt[n-1]) min(cnt[n−1]) 即可。
时间复杂度: O ( n ) O(n) 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]));
}
}
}