Luogu P2460 [SDOI2007] 科比的比赛 题解

题意:给定 n×m 的矩阵 A=(aij) 和长为 m 的数列,矩阵的元素在 [0,1] 上。在矩阵每一行选择一个数,最大化选中的数的乘积的前提下最大化得分,但矩阵每一列至多选择一个数。求最大乘积和对应的最大得分。

考虑状压 DP,设 dpi,j 表示已经处理前 i 列,状态集合为 j 的行已经选定时的最大乘积。

转移

dpi,j=kjdpi1,j{k}ai,k

边界

dpi,0=1

答案

dpm,U

其中 U 是全集。

最大得分容易与乘积同时转移。

时间复杂度 O(nm2n),滚动数组优化空间后可以通过 50 分。

考虑贪心,将矩阵每一行按 ai,j 为第一关键字,sj 为第二关键字降序排序,至多选择前 n 大的位置。

所以排序后将每一行可能被选的位置提出来做一次 DP,至多有 O(n2) 个可能被选的位置,时间复杂度优化为 O(nmlogm+n3logn+n32n),可以通过。

#include <algorithm>
#include <iomanip>
#include <iostream>
using namespace std;
typedef long double ld;
const ld eps = 1e-10;
int n, m;
int w[100005];
int s[100005];
ld a[12][100005];
int b[12][100005];
int id[100005], len;
ld c[12][100005];
ld dp[2][1050];
int f[2][1050];
static inline void solve() {
cin >> n >> m;
int lim = 1 << n;
for (int i = 1; i <= m; ++i)
cin >> w[i];
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
cin >> a[i][j];
b[i][j] = j;
}
sort(b[i] + 1, b[i] + m + 1,
[i](const int x, const int y) {
return (abs(a[i][x] - a[i][y]) < eps)
? (w[x] > w[y])
: (a[i][x] - a[i][y] > eps);
});
for (int j = 1; j <= n && j <= m; ++j)
id[++len] = b[i][j];
}
sort(id + 1, id + len + 1);
len = (int)(unique(id + 1, id + len + 1) - id - 1);
for (int i = 1; i <= len; ++i) {
for (int j = 1; j <= n; ++j)
c[j][i] = a[j][id[i]];
s[i] = w[id[i]];
}
dp[0][0] = 1;
for (int i = 1; i <= len; ++i) {
for (int j = 0; j < lim; ++j) {
dp[i & 1][j] = dp[(i + 1) & 1][j];
f[i & 1][j] = f[(i + 1) & 1][j];
for (int k = 1; k <= n; ++k) {
if (j & (1 << (k - 1))) {
ld val = dp[(i + 1) & 1][j ^ (1 << (k - 1))] * c[k][i];
if (val < eps)
continue;
if (val - dp[i & 1][j] > eps) {
dp[i & 1][j] = val;
f[i & 1][j] = f[(i + 1) & 1][j ^ (1 << (k - 1))] + s[i];
} else if (abs(val - dp[i & 1][j]) < eps)
f[i & 1][j] = max(f[i & 1][j], f[(i + 1) & 1][j ^ (1 << (k - 1))] + s[i]);
}
}
}
}
cout << fixed << setprecision(12) << dp[len & 1][lim - 1] << endl;
cout << f[len & 1][lim - 1] << endl;
}
signed main() {
#ifndef ONLINE_JUDGE
freopen("P2460.in", "r", stdin);
#endif
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
solve();
return 0;
}
posted @   bluewindde  阅读(14)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示