美团秋招笔试真题 - 放它一马 & 信号模拟

放他一马

题目描述

小美会按照编号从小到大的顺序依次遇到 n 只怪物(编号为 1 ~ n),怪物 i(1 ≤ i ≤ n) 的生命为 ai。对于每只怪物,小美都可以选择放走 Ta 或者击败 Ta。如果放走怪物,小美将获得 i 点经验值。如果击败怪物,小美将获得 ai 点经验值,同时将额外获得 (x mod 10) × ai 点经验值,x 为击败怪物数量(包括这一个怪物)。求小美最多可以从这 n 个怪物中获得的经验值。

输入

第一行输入一个整数 n(1 ≤ n ≤ 2 × 105) 表示怪物数。第二行输入 n 个整数 ai(1 ≤ ai ≤ 109) 表示怪物的生命。

输出

输出一个整数表示小美可以获得最高的经验值。

示例1

输入

复制代码
3
5 3 2

输出

复制代码
27

思路和代码

实现:动态规划

  1. 设定f[i][j]表示为前i只怪物,击败j只怪兽(j mod 10)能够获得的最大经验。

  2. 状态转移方程:f[i][j] = max(f[i-1][j] + i, f[i-1][(j-1 + 10) %10] + i *(num+1)),分别表示放走和击败,取其中较大值。

  3. 最终答案就是f[n][j], j取值范围[1,9]中最大值。

优化/注意点:考虑到上述转移方程只和前一轮相关,可以使用一维滚动数组进行压缩。

CPP 复制代码
import sys

def main():
    n = int(sys.stdin.readline().strip())
    a = list(map(int, sys.stdin.readline().split()))

    dp = [0] * 10
    dp_last = [0] * 10

    for i in range(1, n + 1):
        num = a[i - 1]
        for j in range(10):
            if j <= i:
                dp[j] = max(dp_last[j] + i,
                            dp_last[(j - 1 + 10) % 10] + j * num + num)
        dp_last = dp[:]

    res = max(dp_last)
    print(res)


if __name__ == "__main__":
    main()

信号模拟

题目描述

如下所示,有 (2 × n) 个仪器,中间的方块是仪器的主体,每个仪器可以充当接收器或者信号源;主体的左右两侧是两个接线点。现在,我们将左端 (2 × n) 个接线点随机分成 (n) 组,每组各含两个点,并将右端 (2 × n) 个接线点同样随机分成 (n) 组。然后将每组的两个接线点用导线连接。这样一来,我们就得到了一组封闭的信号线路。具体而言:

  • 信号从任一信号源 (i) 出发,通过右侧接线点;
  • 随后,信号通过与右侧接线点连接的导线到达另外一个仪器的左侧接线点,再经过仪器主体到达右侧接线点;
  • 此时,如果这个仪器是接收器,那么就视为接收到了信号(注意,接收到信号不会影响信号继续往后传递)。
  • 这个过程持续进行,最终会形成若干个独立的循环。

现在,记 (x) 表示在所有接收器均能接收到信号的前提下,(2 × n) 个仪器中作为信号源的最少数数量。求解 (x) 的方差。可以证明答案可以表示为一个不可约分数 (p/q),为了避免精度问题,请直接输出整数 (p × q-1 mod M) 作为答案,其中 (M = 998244353),q-1 是满足 q × q-1 ≡ 1 (mod M) 的整数。

输入

每个测试文件均包含多组测试数据。第一行输入一个整数 (T (1 <= T <= 10^4)) 代表数据组数,每组测试数据描述如下:在一行上输入一个整数 (n (1 <= n <= 10^6)) 代表仪器的数量。

输出

对于每组测试数据,新起一行输出一个整数,表示 (x) 的方差对 (M = 998244353) 取模后的结果。

提示

本题中如果需要使用除法的取模,即计算(p * q ^-1 mod M)时,(q^-1)需要使用公式((q^ M-2 MOD M))得到,

示例1

输入

复制代码
3
1
2
3

输出

复制代码
0
887328314
168592380

思路和代码

实现:乘法逆元 + 前缀和

  1. 设X为最少信号源数,E(x)为期望,E(x ^2)为二次期望,D(X) = E(x ^2) - E(x) ^2
  2. inv[k]为k的逆元,设置total1total1[n]1 - n1/2(j -1)的前缀和,设置total2total2[n]1 - n(1/2(j -1))^2的前缀和,
  3. 初始化预计算逆元和前缀和
  4. 对于输入为n的情况下结果即为total[n] - total2[n]
CPP 复制代码
#include<iostream>
#include<vector>
#include<string>
#include <utility> 
#include<algorithm> 
#include<cmath>
#include<map>
#include<stack>
#include<unordered_map>
using namespace std;
typedef long long LL ;

const int MOD = 998244353, N = 1e6 + 10;
// inv[i] 等于 i在MOD下的逆元
LL inv[2 * N];
// total1[i] 表示 1/(2i-1)的前缀和
LL total1[N];
// total2[i]表示(1/(2i-1))^2的前缀和
LL total2[N];




int main() {
    ios::sync_with_stdio(false); 
    cin.tie(nullptr); 
    int T;
    cin >> T;
    int input[T],maxv = 0;
    for (int i = 0; i < T;i++) {
        cin >> input[i];
        maxv = max(maxv, input[i]);
    }
    
    // 最大逆元下标
    int maxv2 = 2 * maxv;
    inv[1] = 1;
    // 递推
    for (int i = 2; i <= maxv2; i++) {
        inv[i] = (MOD - MOD / i) * inv[MOD % i] % MOD;
    }
    
    // 预处理前缀和
    total1[0] = 0;
    total2[0] = 0;
    // 预计算前缀和
    for (int j = 1; j <= maxv; j++) {
        LL x = inv[2 * j - 1];
        total1[j] = (total1[j - 1] + x) % MOD;
        total2[j] =  (total2[j-1] + x * x % MOD) %MOD;
    }
    
    for (int i = 0; i < T; i++) {
        int n = input[i];
        // 方差公式 D(X) = sum1[n] = sum2[2]
        long long res = (total1[n] - total2[n] + MOD) % MOD;
        cout << res << endl;
    }
    return 0;
}
相关推荐
江畔柳前堤7 小时前
大语言模型分布式训练:从并行策略到万卡工程的系统梳理
人工智能·分布式·深度学习·算法·目标检测·机器学习·语言模型
Forever Nore8 小时前
LeetCode 4 寻找两个正序数组的中位数 - 二分
算法·leetcode
罗西的思考10 小时前
【OpenClaw具身硬件】MiniClaw 阅读笔记---(1)基础
人工智能·算法·机器学习
蛋先生DX10 小时前
大模型参数存储格式揭秘:BF不是男朋友
深度学习·算法·llm
爱跳舞的烤冷面11 小时前
自学嵌入式第22天(数据结构——哈希)
数据结构·算法·哈希算法
猎嘤一号11 小时前
博弈论(Game Theory)的理论、算法与工程
人工智能·算法·安全·博弈论
月光船幽幽11 小时前
影子模式下保护 logits 不被修改
人工智能·python·算法
马拉AI11 小时前
腾讯开源 Agent 记忆系统,AI“换对话就忘”的问题有了新解法(附安装使用教程)
人工智能·算法·开源·科研
地平线开发者13 小时前
征程6工具链模型X86推理方式说明
算法
地平线开发者13 小时前
【征程6】校准量化中HistogramObserver解析
算法