得物笔试 得物秋招 得物笔试题 1011

笔试时间:2025年10月11日

往年笔试合集:

2023春招秋招笔试合集

2024春招秋招笔试合集

第一题:挖掘宝石

题目: 小明设计了一个挖掘宝石的小游戏。在游戏中有红宝石、蓝宝石、绿宝石等多种不同类型的宝石,当然也有昂贵的钻石。现在给出一个地图,在地图上有N种不同的宝石。每一种宝石都有一颗或者多颗,同一种宝石每一颗的价值都是相同的。此外,每一种宝石都有一个挖掘时间。在给定的时间内,哪一个玩家挖掘的宝石的总价值最大就是游戏的赢家。现在给出N类不同宝石的数量以及每一类宝石中每一颗的价值和挖掘时间,并且给出一个总的游戏时间T。在不考虑竞争对手的情况下,请问可以得到的最大价值是多少?

输入描述

第1行输入一个正整数N和一个正整数T,分别表示宝石类型的数量和总游戏时间(分钟),两者之间用空格隔开。1 ≤ N ≤ 100,1 ≤ T ≤ 1000。从第2行到第N+1行每一行三个正整数X[i],Y[i]和Z[i],分别表示第i类宝石的数量、第i类宝石中一颗宝石的价值和挖掘时间(分钟)。X[i]、Y[i]和Z[i]均不超过100。

输出描述

输出可以得到的最大价值。

样例输入

3 10

2 5 5

3 4 3

2 8 6

样例输出

12

参考题解

解题思路: 二进制拆分:将每种宝石的数量拆分成若干个"二进制数"对应的数量(如1,2,4,8,…),这样可以用这些拆分后的"物品"(每个"物品"代表一定数量的该类宝石),通过类似0-1背包的方式来处理多重背包问题,减少时间复杂度。动态规划数组dp:dp[j]表示使用j分钟能获得的最大价值。初始时所有元素为0。状态转移:对于每类宝石拆分后的每个"物品",从后往前遍历时间(避免重复选择),如果当前剩余时间j大于等于该"物品"的挖掘时间cost,则更新dp[j]为dp[j]和dp[j-cost]+value中的较大值。

C++:

#include <bits/stdc++.h>
using namespace std;

int main() {
    int N, T;
    cin >> N >> T;
    vector<int> dp(T + 1, 0);
    
    for (int i = 0; i < N; ++i) {
        int X, Y, Z;
        cin >> X >> Y >> Z;
        
        // 二进制拆分处理多重背包
        for (int k = 1; X > 0; k <<= 1) {
            int num = min(k, X);
            X -= num;
            int cost = Z * num;  // 该份宝石的总挖掘时间
            int value = Y * num; // 该份宝石的总价值
            
            // 0-1背包思路,从后往前遍历
            for (int j = T; j >= cost; --j) {
                dp[j] = max(dp[j], dp[j - cost] + value);
            }
        }
    }
    
    cout << dp[T] << endl;
    return 0;
}

Java:

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int N = scanner.nextInt();
        int T = scanner.nextInt();
        int[] dp = new int[T + 1];
        
        for (int i = 0; i < N; ++i) {
            int X = scanner.nextInt(); // 宝石数量
            int Y = scanner.nextInt(); // 单颗价值
            int Z = scanner.nextInt(); // 单颗挖掘时间
            
            // 二进制拆分处理多重背包
            for (int k = 1; X > 0; k <<= 1) {
                int num = Math.min(k, X);
                X -= num;
                int cost = Z * num;  // 该份宝石的总挖掘时间
                int value = Y * num; // 该份宝石的总价值
                
                // 0-1背包思路,从后往前遍历
                for (int j = T; j >= cost; --j) {
                    dp[j] = Math.max(dp[j], dp[j - cost] + value);
                }
            }
        }
        
        System.out.println(dp[T]);
        scanner.close();
    }
}

Python:

N, T = map(int, input().split())
dp = [0] * (T + 1)

for _ in range(N):
    X, Y, Z = map(int, input().split())
    
    # 二进制拆分处理多重背包
    k = 1
    while X > 0:
        num = min(k, X)
        X -= num
        cost = Z * num   # 该份宝石的总挖掘时间
        value = Y * num  # 该份宝石的总价值
        
        # 0-1背包思路,从后往前遍历
        for j in range(T, cost - 1, -1):
            dp[j] = max(dp[j], dp[j - cost] + value)
        
        k <<= 1

print(dp[T])

第二题:相似

小A觉得文本中有一些微小错误不会影响人类的正常阅读。同样的,他也希望人工智能也能达成这样的目标。为此他想制作一些测试数据集。小A认为微小错误是这样的:要么只有一个字符被改变;要么是仅有一个字符错位了,被移动到字符串其他地方,而其他字符相对顺序不变。小A认为上述两项错误只能选有最多一项,否则将会让人类也难以辨认原来的单词。小A想验证一下自己的数据集,看看是否都符合此种要求的错误。

输入描述

第一行一个整数t表示数据组数。

对每组数据:第一行1个整数n,表示笔记的长度。

第二行长为n的英文字符串S,表示正确的单词。

第三行长为n的英文字符串T,表示微小错误的单词。

1 ≤ n ≤ 5000,1 ≤ t ≤ 20

输出描述

对每组数据,输出一行Yes或No表示T是否是S发生微小错误后的字符串。

样例输入

3

5

Ababa

aAbab

2

Ab

Ac

2

Ab

Cd

样例输出

Yes

Yes

No

样例说明: 第一组,将最后一个a提到最前面即可。第二组,将最后一个b替换成c即可。第三组无论如何无法通过一次微小错误完成。

参考题解

字符替换判断:遍历两个字符串,统计对应位置不同字符的数量,若数量为1,则满足替换错误条件。字符移动判断:首先检查字符频率,若两个字符串字符频率不同,直接不满足。然后找到两个字符串首尾开始不同的位置l和r,若l>=r,说明无错位。最后检查两种移动情形:s中位置l的字符移到更右位置,或s中位置r的字符移到更左位置,若其中一种情形满足,则符合移动错误条件。

C++:

#include <bits/stdc++.h>
using namespace std;

// 检查是否只替换了一个字符
bool isReplace(string s, string t) {
    int diff = 0;
    for (int i = 0; i < s.length(); ++i) {
        if (s[i] != t[i]) {
            diff++;
        }
    }
    return diff == 1;
}

// 检查是否通过一次字符移动得到
bool isMove(string s, string t) {
    if (s == t) {
        return false; // 没变化不算
    }
    
    // 1. 检查字符频率是否相同
    vector<int> cnt(256, 0);
    for (char c : s) {
        cnt[c]++;
    }
    for (char c : t) {
        cnt[c]--;
    }
    for (int count : cnt) {
        if (count != 0) {
            return false;
        }
    }
    
    int n = s.length();
    int l = 0, r = n - 1;
    
    // 2. 找出首尾开始不同的位置
    while (l < n && s[l] == t[l]) {
        l++;
    }
    while (r >= 0 && s[r] == t[r]) {
        r--;
    }
    
    if (l >= r) {
        return false; // 说明没发生错位
    }
    
    // 3. 检查"左移一位"或"右移一位"情形
    // case1: s[l] 移到更右的位置
    bool moveRight = (s[l] == t[r]);
    for (int i = l + 1; i <= r; ++i) {
        if (s[i] != t[i - 1]) {
            moveRight = false;
        }
    }
    
    // case2: s[r] 移到更左的位置
    bool moveLeft = (s[r] == t[l]);
    for (int i = l; i < r; ++i) {
        if (s[i] != t[i + 1]) {
            moveLeft = false;
        }
    }
    
    return moveLeft || moveRight;
}

int main() {
    int T;
    cin >> T;
    
    while (T-- > 0) {
        int n;
        string s, t;
        cin >> n >> s >> t;
        
        if (isReplace(s, t) || isMove(s, t)) {
            cout << "Yes" << endl;
        } else {
            cout << "No" << endl;
        }
    }
    
    return 0;
}

Java:

import java.util.Scanner;

public class Main {
    // 检查是否只替换了一个字符
    public static boolean isReplace(String s, String t) {
        int diff = 0;
        for (int i = 0; i < s.length(); ++i) {
            if (s.charAt(i) != t.charAt(i)) {
                diff++;
            }
        }
        return diff == 1;
    }
    
    // 检查是否通过一次字符移动得到
    public static boolean isMove(String s, String t) {
        if (s.equals(t)) {
            return false; // 没变化不算
        }
        
        // 1. 检查字符频率是否相同
        int[] cnt = new int[256];
        for (char c : s.toCharArray()) {
            cnt[c]++;
        }
        for (char c : t.toCharArray()) {
            cnt[c]--;
        }
        for (int count : cnt)

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

2025 春招笔试合集 文章被收录于专栏

2025打怪升级记录,大厂笔试合集 C++, Java, Python等多种语言做法集合指南

全部评论

相关推荐

点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务