【备战秋招】每日一题:2023.08.22-拼多多服务端研发笔试-第四题-塔子哥的好数组对

为了更好的阅读体检,可以查看我的算法学习网
在线评测链接: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=2naiai1)+(i=2nbibi1) 的和最大时,称这两个数组是一个好数组对。

塔子哥允许你交换数组 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(1T10) ,表示数据组数。
接下来每组数据,

第一行,一个整数 n ( 2 ≤ n ≤ 1 0 5 ) n(2\leq n\leq 10^5) n(2n105) 表示数组大小。

第二行, n n n 个整数,表示数组 a a a n n n 个数, 1 ≤ a i ≤ 1 0 9 1\leq a_i\leq 10^9 1ai109

第三行, n n n 个整数,表示数组 b b b n n n 个数, 1 ≤ b i ≤ 1 0 9 1\leq b_i\leq 10^9 1bi109

保证 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[i1][0]+abs(a[i]a[i1])+abs(b[i]b[i1]),val[i1][1]+abs(a[i]b[i1])+abs(b[i]a[i1]))

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[i1][0]+abs(b[i]a[i1])+abs(a[i]b[i1]),val[i1][1]+abs(a[i]a[i1])+abs(b[i]b[i1]))

此外,我们还需要记录每个状态需要交换的次数。

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[n1][0],val[n1][1]) 对应的 c n t [ n − 1 ] cnt[n-1] cnt[n1] ,如果两者 v a l [ n − 1 ] [ 0 ] = v a l [ n − 1 ] [ 1 ] val[n-1][0]=val[n-1][1] val[n1][0]=val[n1][1] ,则取 min ⁡ ( c n t [ n − 1 ] ) \min(cnt[n-1]) min(cnt[n1]) 即可。

时间复杂度: 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]));
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

塔子哥学算法

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值