建造防风林
作者:互联网
题目描述:给你一个\(n \times m\)的二维矩阵\(grid\),再给你一个整数\(k\),你可以从二维矩阵中任意选择\(k\)行出来,组合成新的二维矩阵,对于新的二维矩阵,其每一列的最大值的最小值最大是多少。
数据范围:\(1 \leq n \leq 10^5 , 1 \leq m \leq 5 , 1 \leq k \leq 5 , 1\leq grid_{i , j} \leq 10^9\)。
思路:根据题意可以很明显的知道是二分答案,我们首先二分最大值,然后将原数组中小于最大值的置为\(0\),将大于等于最大值的置为\(1\),考虑到列数不超过\(5\),可以状压,将每一行压成一个不超过\(31(2^5 - 1)\)的整数,那么问题就变成在这\(n\)个数中选择\(k\)个数使得其或运算的值为\(2^m - 1\)是否可能。该问题显然有以下转移方程:
\[f_{i , j} = max(f_{i - 1 , j} , f_{i - 1 , j - 1} | val_i) \]最后只需要判断\(f_{n , k} == 2^m - 1\)是否成立即可。该转移过程可以使用滚动数组优化空间。
空间复杂度:\(O(nm)\)
时间复杂度:\(O(n(m + k)log10^9)\)
参考代码:
#include<bits/stdc++.h>
using namespace std;
bool check(vector<int>& c, int n, int m, int k) {
vector<vector<int>>f(2, vector<int>(k + 1, 0));
int op = 0;
for (int i = 0; i < n; ++i) {
for (int j = 1; j <= k; ++j) {
f[op][j] = max(f[op ^ 1][j], f[op ^ 1][j - 1] | c[i]);
}
op ^= 1;
}
return f[op ^ 1][k] == (1 << m) - 1;
}
void solve() {
int n, m, k;
cin >> n >> m >> k;
vector<vector<int>>a(n, vector<int>(m, 0));
vector<int>c(n);
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cin >> a[i][j];
}
}
int lr = 1, rs = 1e9 + 7, res = 1;
while (lr <= rs) {
int mid = 1ll * (lr + rs) / 2;
for (int i = 0; i < n; ++i) {
c[i] = 0;
for (int j = 0; j < m; ++j) {
if (a[i][j] < mid) continue;
c[i] |= (1 << j);
}
}
if (check(c, n, m, k)) res = mid, lr = mid + 1;
else rs = mid - 1;
}
cout << res << '\n';
return;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int T = 1;
//cin >> T;
while (T--) solve();
return 0;
}
/*
7 5 3
5 4 6 9 8
8 5 3 8 4
4 5 8 7 4
4 10 5 7 1
8 1 3 7 7
2 6 6 3 4
10 1 6 8 2
4 3 2
4 2 7
5 1 6
4 3 3
1 2 5
3 4 2
3 4 2 1
2 2 5 3
1 2 4 1
*/
标签:10,int,矩阵,最大值,建造,leq,vector,防风林 来源: https://www.cnblogs.com/cherish-/p/16365447.html