题目解析
小 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 获得的最大得分。
解决思路
-
数据预处理
- 读取 s 个玩家的投资策略,并按奖励点归类,将对某个奖励点的所有玩家出价存储在一个数组中。
- 对于每个奖励点,将玩家的出价从小到大排序。
-
动态规划建模
- 令
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]
。
- 不投资当前奖励点,继承
- 令
-
状态转移
- 初始化
dp[i][j]
为dp[i-1][j]
,即不投资时的得分。 - 遍历所有资金
j
,然后遍历k
(对手在当前奖励点的出价列表),检查是否可以通过2 * 对手出价[k] + 1
的投资赢得该奖励点,并更新dp[i][j]
。
- 初始化
-
求解最优解
- 计算
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 的最坏情况下仍然是可接受的。