【笔试题汇总】滴滴笔试题题解 2025.3.9

题目解析

小 C正在玩一款名叫《超级大富翁》的游戏。游戏中有n个奖励点,每局游戏由两名玩家来争夺这些奖励点。每名玩家有 m 元,可以向第i个奖励点投资 a,元去争夺这个奖励点,使得投资总钱数不超过 m。如果一名玩家向第i个奖励点投资的钱数严格大于对手投资钱数的两倍,那么这名玩家就占领了这个奖励点,获得 1分。
现在小 C即将和其他s名玩家两两进行游戏,这s场游戏的投资方案必须相司。小C 通过某些途径得知了其他s名玩家即将使用的策略,他想知道他应该使用什么策略来最大化自己的总分。由于答案可能不唯一,你只需要输出小 C 总分的最大值。
1<=n<=100,1<=m<=20000,s <=100
输入描述
输入第一行包含三个正整数 s,n,m,分别表示除了小 C 以外的玩家人数、奖励点数和每名玩家拥有的钱数。接下来s行,每行n个非负整数,表示一名玩家的策略,其中第i个数 ai 表示这名玩家向第i个奖励点投资的钱数。
输出描述
输出一行一个非负整数,表示小 C 获得的最大得分。

解决思路

  1. 数据预处理

    • 读取 s 个玩家的投资策略,并按奖励点归类,将对某个奖励点的所有玩家出价存储在一个数组中。
    • 对于每个奖励点,将玩家的出价从小到大排序。
  2. 动态规划建模

    • dp[i][j] 表示在前 i 个奖励点中,使用 j 元资金所能获得的最大得分。
    • 采用 0/1 背包的方式进行转移:
      • 不投资当前奖励点,继承 dp[i-1][j]
      • 尝试对当前奖励点进行投资,如果投资 x 元,并且 x > 2 * 对手出价[k],则可以获得 1 分。
      • 由于 x 需要符合资金限制,我们遍历 j + 2 * 对手出价[k] + 1 <= m,并更新 dp[i][j + 2 * 对手出价[k] + 1]
  3. 状态转移

    • 初始化 dp[i][j]dp[i-1][j],即不投资时的得分。
    • 遍历所有资金 j,然后遍历 k (对手在当前奖励点的出价列表),检查是否可以通过 2 * 对手出价[k] + 1 的投资赢得该奖励点,并更新 dp[i][j]
  4. 求解最优解

    • 计算 dp[n][j]0 <= j <= m 取值范围内的最大值,即最终的最高得分。

代码解析

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

int dp[102][20004], nu[102][102];

void solve() {
    int s, n, m;
    cin >> s >> n >> m;
    vector<vector<int>> pth(n + 1);
    
    // 读取输入并整理数据
    for (int i = 1; i <= s; i++) {
        for (int j = 1; j <= n; j++) {
            cin >> nu[i][j];
            pth[j].push_back(nu[i][j]);
        }
    }
    
    // 对每个奖励点的出价进行排序
    for (int i = 1; i <= n; i++) {
        sort(pth[i].begin(), pth[i].end());
        
        // 初始化 DP 数组
        for (int j = 0; j <= m; j++)
            dp[i][j] = dp[i - 1][j];
        
        // 进行 DP 状态转移
        for (int j = 0; j <= m; j++) {
            for (int k = 0; k < s; k++) {
                int cost = pth[i][k] * 2 + 1;
                if (j + cost <= m)
                    dp[i][j + cost] = max(dp[i - 1][j] + i * (k + 1), dp[i][j + cost]);
            }
        }
    }
    
    // 找到最大得分
    int ans = 0;
    for (int i = 0; i <= m; i++)
        ans = max(ans, dp[n][i]);
    
    cout << ans << endl;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    solve();
    return 0;
}

复杂度分析

  • 排序阶段:对于每个奖励点,对 s 个出价进行排序,复杂度为 O ( n s log ⁡ s ) O(n s \log s) O(nslogs)
  • 动态规划部分
    • dp[i][j] 计算总复杂度 O ( n × m × s ) O(n \times m \times s) O(n×m×s)
    • 每个奖励点的决策复杂度为 O ( m × s ) O(m \times s) O(m×s)

总时间复杂度为 O ( n s log ⁡ s + n m s ) O(n s \log s + n m s) O(nslogs+nms),在 n = 100 , m = 20000 , s = 100 n=100, m=20000, s=100 n=100,m=20000,s=100 的最坏情况下仍然是可接受的。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值