阿里巴巴 算法岗 笔试真题 5月23号-分组计数

分组计数(C++/Py/Java /Js/Go)题解

阿里研发岗 0523笔试 第一题

题目内容

给定 nnn 个人的权值序列 a1,a2,...,ana_1,a_2,\dots,a_na1,a2,...,an,保证 aaa 已按非降序排列。

需要将所有人分成若干组,每组人数只能为 111 或 222。规则如下:

  1. 单人一组不受限制。
  2. 两人一组时,必须选择下标相邻的两个人 (i−1,i)(i-1,i)(i−1,i),并满足 ∣ai−ai−1∣≤K|a_i - a_{i-1}| \le K∣ai−ai−1∣≤K。
    请你计算共有多少种合法的分组方案,答案对 109+710^9 + 7109+7 取模。

输入描述

每个测试文件均包含多组测试数据。第一行输入一个整数 T (1≤T≤105)T\ (1 \le T \le 10^5)T (1≤T≤105) 表示数据组数,每组测试数据描述如下:

第一行输入两个整数 n,K (1≤n≤2×105, 0≤K≤109)n, K\ (1 \le n \le 2 \times 10^5,\ 0 \le K \le 10^9)n,K (1≤n≤2×105, 0≤K≤109)。

第二行输入 nnn 个整数 a1,a2,...,an (∣ai∣≤1018)a_1,a_2,\dots,a_n\ (|a_i| \le 10^{18})a1,a2,...,an (∣ai∣≤1018),并保证 a1≤a2≤⋯≤ana_1 \le a_2 \le \dots \le a_na1≤a2≤⋯≤an。

保证所有测试中 nnn 的总和不超过 2×1052 \times 10^52×105。

输出描述

输出 TTT 行,每行输出一个整数,表示合法分组方案数对 109+710^9 + 7109+7 取模后的结果。

样例1

输入

复制代码
3
4 1
1 2 4 10
4 0
1 2 3 4
5 2
1 1 2 4 7

输出

复制代码
2
1
5

说明

第一组:只有相邻的 (1,2)(1,2)(1,2) 满足差值不超过 KKK,因此方案为:全单人;或 (1,2)(1,2)(1,2) 配对其余单人,共 222 种。

第二组:相邻差均大于 000,无法配对,只能全单人,答案为 111。

题解和思路

思路

实现思路:动态规划

  1. 定义dp其中dp[i]表示i分组之后可以得到的方案数。
  2. 状态转移:
    • a[i] - a[i-1] <= k时, 状态转移dp[i] = dp[i-1] + dp[i -2]
    • a[i] - a[i-1] > k时, 状态转移dp[i] = dp[i-1]
  3. 算法总体时间复杂度为O(n)

C++

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

const long MOD = 1e9 + 7;

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    int T;
    cin >> T;
    while (T--) {
        int n, k;
        cin >> n >> k;
        vector<long> a(n);
        for (int i = 0; i < n; i++) {
            cin >> a[i];
        }
        vector<long> dp(n + 1, 0);
        dp[0] = 1;
        // 动态规划
        for (int i = 1; i <= n; i++) {
            dp[i] = dp[i-1];
            if (i > 1 && a[i-1] - a[i-2] <= k) {
                dp[i] = (dp[i] + dp[i-2]) & MOD;
            } 
        }
        cout << dp[n] << endl;
    }
    return 0;
}

Java

java 复制代码
import java.io.*;
import java.util.*;

public class Main {
    static final long MOD = 1000000007L;

    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        int T = Integer.parseInt(br.readLine());

        while (T-- > 0) {
            String[] strs = br.readLine().split(" ");
            int n = Integer.parseInt(strs[0]);
            int k = Integer.parseInt(strs[1]);

            long[] a = new long[n];
            strs = br.readLine().split(" ");
            for (int i = 0; i < n; i++) {
                a[i] = Long.parseLong(strs[i]);
            }

            long[] dp = new long[n + 1];
            dp[0] = 1;

            // 动态规划
            for (int i = 1; i <= n; i++) {
                dp[i] = dp[i - 1];
                if (i > 1 && a[i - 1] - a[i - 2] <= k) {
                    dp[i] = (dp[i] + dp[i - 2]) & MOD;
                }
            }

            System.out.println(dp[n]);
        }
    }
}

python

python 复制代码
MOD = 1000000007

T = int(input())

for _ in range(T):
    n, k = map(int, input().split())
    a = list(map(int, input().split()))

    dp = [0] * (n + 1)
    dp[0] = 1

    # 动态规划
    for i in range(1, n + 1):
        dp[i] = dp[i - 1]
        if i > 1 and a[i - 1] - a[i - 2] <= k:
            dp[i] = (dp[i] + dp[i - 2]) & MOD

    print(dp[n])

Javascript

js 复制代码
const readline = require("readline");

const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
});

const input = [];

rl.on("line", line => input.push(line));

rl.on("close", () => {
    const MOD = 1000000007;

    let idx = 0;
    const T = Number(input[idx++]);

    const ans = [];

    for (let t = 0; t < T; t++) {
        const [n, k] = input[idx++].split(" ").map(Number);
        const a = input[idx++].split(" ").map(Number);

        const dp = new Array(n + 1).fill(0);
        dp[0] = 1;

        // 动态规划
        for (let i = 1; i <= n; i++) {
            dp[i] = dp[i - 1];
            if (i > 1 && a[i - 1] - a[i - 2] <= k) {
                dp[i] = (dp[i] + dp[i - 2]) & MOD;
            }
        }

        ans.push(dp[n]);
    }

    console.log(ans.join("\n"));
});

Go

go 复制代码
package main

import (
	"bufio"
	"fmt"
	"os"
)

const MOD int64 = 1000000007

func main() {
	in := bufio.NewReader(os.Stdin)

	var T int
	fmt.Fscan(in, &T)

	for ; T > 0; T-- {
		var n, k int
		fmt.Fscan(in, &n, &k)

		a := make([]int64, n)
		for i := 0; i < n; i++ {
			fmt.Fscan(in, &a[i])
		}

		dp := make([]int64, n+1)
		dp[0] = 1

		// 动态规划
		for i := 1; i <= n; i++ {
			dp[i] = dp[i-1]
			if i > 1 && a[i-1]-a[i-2] <= int64(k) {
				dp[i] = (dp[i] + dp[i-2]) & MOD
			}
		}

		fmt.Println(dp[n])
	}
}