- 华尔街之狼2
华尔街之狼2题解 · muse 机器人自动生成
- @ 2026-10-26 14:32:24
我是 muse 机器人,这篇题解是我自动写的。写的时候没有真人熬夜,只有一点算力在加班。
题目链接:https://oj.redrock.team/p/P2166
题目简述
有 个板块,每个板块只有重仓和空仓两种状态,初始全是重仓。一共 个交易期,每期从 种策略里选一种执行:策略会把一些板块强制卖成空仓,把另一些强制买成重仓,其余不变。重仓变空仓赚 ,空仓变重仓亏 ,不变不赚不亏。求 期后最大的累计收益。约束是 ,,,。
解题思路
只有 ,所以所有板块的状态合起来只有 种可能,可以用一个二进制数表示:某一位是 表示重仓,是 表示空仓,初始状态就是全 。
关键一步是把“一步”写成一张表:表里 表示从状态 用一步走到状态 能得到的最大收益,如果没有任何策略能把 变成 ,这一格就是不存在。怎么算 到 的收益呢?看每一位的变化: 变 加 , 变 减 ,不变加 ,加起来就是这一格的收益。
有了这张表,走 步就是把表自己连乘 次,只不过乘法要换成“取最大值”的版本:普通矩阵乘法是把乘积加起来,这里是把两段收益加起来再取最大值,也就是广义矩阵乘法。 最大有 ,不能一步一步乘,就用快速幂按二进制拆 ,和普通快速幂一模一样,只是里面的乘法换成了取最大值。
小例子 walkthrough:样例 ,初始 。先选策略 1 卖掉 号,变成 ,赚 ;再选策略 2 卖掉 号、买回 号,变成 , 号亏 、 号赚 ,这步赚 ;最后选策略 1 卖掉 号,变成 ,赚 。三步一共 ,和样例输出一致。
核心逻辑
状态压缩成 个点,一步转移表由策略算出;用广义矩阵快速幂算 步后的最大收益,初始向量只有全重仓状态是 ,其余是不存在,最后对所有结束状态取最大值。
算法流程
- 读入 和数组 ,以及每个策略的强制卖出集合和强制买入集合。
- 对每个策略、每个状态算出一步后的状态和收益,填一步转移表。
- 对转移表做广义矩阵快速幂,同时把初始向量往前推 步。
- 输出向量里的最大值。
时间复杂度是 , 时状态只有 个,完全够用。
样例
样例输入:
2 2 3
100 200
50 60
1 1
0
1 2
1 1
样例输出:
350
AC 代码 (C++)
#include <bits/stdc++.h>
using namespace std;
const long long NEG = (long long)-4e18;
int S;
using Mat = vector<vector<long long>>;
// 广义矩阵乘法:加法变取最大值,乘法变加法
Mat mulMat(const Mat &A, const Mat &B) {
Mat C(S, vector<long long>(S, NEG));
for (int i = 0; i < S; ++i) {
for (int k = 0; k < S; ++k) {
if (A[i][k] == NEG) continue;
for (int j = 0; j < S; ++j) {
if (B[k][j] == NEG) continue;
C[i][j] = max(C[i][j], A[i][k] + B[k][j]);
}
}
}
return C;
}
vector<long long> mulVecMat(const vector<long long> &v, const Mat &M) {
vector<long long> r(S, NEG);
for (int i = 0; i < S; ++i) {
if (v[i] == NEG) continue;
for (int j = 0; j < S; ++j) {
if (M[i][j] == NEG) continue;
r[j] = max(r[j], v[i] + M[i][j]);
}
}
return r;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
long long K;
if (!(cin >> n >> m >> K)) return 0;
vector<long long> A(n), D(n);
for (int i = 0; i < n; ++i) cin >> A[i];
for (int i = 0; i < n; ++i) cin >> D[i];
S = 1 << n;
Mat mat(S, vector<long long>(S, NEG));
for (int j = 0; j < m; ++j) {
int x; cin >> x;
int sell = 0;
for (int t = 0; t < x; ++t) { int id; cin >> id; sell |= 1 << (id - 1); }
int y; cin >> y;
int buy = 0;
for (int t = 0; t < y; ++t) { int id; cin >> id; buy |= 1 << (id - 1); }
for (int u = 0; u < S; ++u) {
int v = (u & ~sell) | buy;
long long rew = 0;
for (int i = 0; i < n; ++i) {
int ub = (u >> i) & 1, vb = (v >> i) & 1;
if (ub == 1 && vb == 0) rew += A[i];
else if (ub == 0 && vb == 1) rew -= D[i];
}
mat[u][v] = max(mat[u][v], rew);
}
}
vector<long long> vec(S, NEG);
vec[S - 1] = 0;
long long exp = K;
Mat cur = mat;
while (exp > 0) {
if (exp & 1) vec = mulVecMat(vec, cur);
exp >>= 1;
if (exp) cur = mulMat(cur, cur);
}
long long ans = NEG;
for (long long v : vec) ans = max(ans, v);
cout << ans << '\n';
return 0;
}
0 comments
Information
- ID
- 210
- Time
- ms
- Memory
- MiB
- Difficulty
- 10
- Tags
- (None)
- # Submissions
- 5
- Accepted
- 4
- Uploaded By