【备战秋招】2024年小米秋招笔试题第一套-第二题

📌 点击直达笔试专栏 👉《大厂笔试突围》

💻 春秋招笔试突围在线OJ 👉 笔试突围OJ

02. K小姐的魔法花园

问题描述

K 小姐是一位热爱园艺的魔法师。她有一个神奇的花园,里面种植着 n n n 朵魔法花。每朵花都有一个魔力值,初始时第 i i i 朵花的魔力值为 A [ i ] A[i] A[i]。K 小姐想要让花园的总魔力值成为一个特定数字 x x x 的倍数。

为了达成目标,K 小姐可以进行两种魔法操作:

  1. 将一朵花从花园中移除。
  2. 对一朵花施加增强魔法,使其魔力值增加 1。

K 小姐想知道,最少需要进行多少次魔法操作,才能使花园中剩余的花的魔力值之和成为 x x x 的倍数(如果移除所有的花,总和视为 0,也是 x x x 的倍数)。

输入格式

第一行包含两个正整数 n n n 和 x x x,分别表示魔法花的数量和目标倍数。

第二行包含 n n n 个正整数 A 1 , A 2 , ... , A n A_1, A_2, \ldots, A_n A1,A2,...,An,表示每朵魔法花的初始魔力值。

输出格式

输出一个整数,表示 K 小姐需要进行的最少魔法操作次数。

样例输入

复制代码
1 3
4

3 5
2 7 6

样例输出

复制代码
1

2
样例 解释说明
样例1 直接将唯一的魔法花移除,此时花园的总魔力值为0,是3的倍数,操作次数为1
样例2 移除第2朵花(魔力值7),剩余花的总魔力值为2+6=8,需要增强2次变为10(5的倍数),总操作次数为1+2=3。或者移除第1、3朵花,总操作次数为2

数据范围

  • 1 ≤ n ≤ 1000 1 \leq n \leq 1000 1≤n≤1000
  • 1 ≤ x ≤ 1000 1 \leq x \leq 1000 1≤x≤1000
  • 1 ≤ A i ≤ 1000 1 \leq A_i \leq 1000 1≤Ai≤1000

题解

这是一个经典的同余动态规划问题。对于每朵花,都有两种选择:移除或保留。

关键观察:我们只关心魔力值之和模 x x x 的余数。设当前剩余魔力值之和为 S S S,那么需要增强 ( x − S   m o d   x )   m o d   x (x - S \bmod x) \bmod x (x−Smodx)modx 次才能使总和成为 x x x 的倍数。

使用记忆化搜索解决:

  1. 状态定义: dfs ( i , mod ) \text{dfs}(i, \text{mod}) dfs(i,mod) 表示处理完前 i i i 朵花,当前魔力值之和模 x x x 等于 mod \text{mod} mod 时的最小操作次数
  2. 状态转移:对于第 i i i 朵花,可以选择移除(操作次数+1)或保留
  3. 边界条件:当处理完所有花时,返回需要增强的次数

时间复杂度为 O ( n × x ) O(n \times x) O(n×x),空间复杂度为 O ( n × x ) O(n \times x) O(n×x)。

参考代码

  • Python
python 复制代码
import sys
input = lambda: sys.stdin.readline().strip()

def solve():
    # 读取输入
    n, x = map(int, input().split())
    nums = list(map(int, input().split()))
    
    # 计算初始总和的余数
    total = sum(nums) % x
    
    # 记忆化数组
    memo = {}
    
    def dp(pos, mod):
        # 如果处理完所有花
        if pos == n:
            return (x - mod) % x
        
        # 如果已经计算过
        if (pos, mod) in memo:
            return memo[(pos, mod)]
        
        # 选择移除当前花
        res = dp(pos + 1, mod) + 1
        
        # 选择保留当前花
        new_mod = (mod + nums[pos]) % x
        res = min(res, dp(pos + 1, new_mod))
        
        memo[(pos, mod)] = res
        return res
    
    print(dp(0, 0))

solve()
  • Cpp
cpp 复制代码
#include 
#include 
#include 
using namespace std;

int n, x;
vector nums;
int memo[1005][1005];

// 递归求解最小操作数
int dp(int pos, int mod) {
    // 处理完所有花朵
    if (pos == n) {
        return (x - mod) % x;
    }
    
    // 已经计算过的状态
    if (memo[pos][mod] != -1) {
        return memo[pos][mod];
    }
    
    // 移除当前花朵
    int res = dp(pos + 1, mod) + 1;
    
    // 保留当前花朵
    int new_mod = (mod + nums[pos]) % x;
    res = min(res, dp(pos + 1, new_mod));
    
    return memo[pos][mod] = res;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    cin >> n >> x;
    nums.resize(n);
    
    int total = 0;
    for (int i = 0; i < n; i++) {
        cin >> nums[i];
        total = (total + nums[i]) % x;
    }
    
    // 初始化记忆化数组
    memset(memo, -1, sizeof(memo));
    
    cout << dp(0, 0) << "\n";
    
    return 0;
}
  • Java
java 复制代码
import java.util.Scanner;

public class Main {
    static int n, x;
    static int[] nums;
    static int[][] memo;
    
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        
        // 读取输入数据
        n = sc.nextInt();
        x = sc.nextInt();
        nums = new int[n];
        
        int total = 0;
        for (int i = 0; i < n; i++) {
            nums[i] = sc.nextInt();
            total = (total + nums[i]) % x;
        }
        
        // 初始化记忆化数组
        memo = new int[n][x];
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < x; j++) {
                memo[i][j] = -1;
            }
        }
        
        System.out.println(solve(0, 0));
        sc.close();
    }
    
    // 动态规划求解
    static int solve(int pos, int mod) {
        // 处理完所有花朵
        if (pos == n) {
            return (x - mod) % x;
        }
        
        // 记忆化查询
        if (memo[pos][mod] != -1) {
            return memo[pos][mod];
        }
        
        // 移除花朵
        int result = solve(pos + 1, mod) + 1;
        
        // 保留花朵
        int newMod = (mod + nums[pos]) % x;
        result = Math.min(result, solve(pos + 1, newMod));
        
        return memo[pos][mod] = result;
    }
}