题目 链接
题意
给出两个a,b序列,为每一个a[i]选一个b[j]得到他们的按位与(即a[i]&b[j]),把这些所有的结果按位或,求最小值。
简析
因为n,m都不大于200,可以先读入然后把每个组合的按位与求出来,就能够得到一个nm的矩阵,记录着每个按位与。
然后问题就转化为,对于一个nm的矩阵,每行选一个数字出来,这n个数字的按位或最小。
要从答案出发!因为每个数字都不大于29,所以直接遍历答案从0 ~ 29,然后找出第一个合法的就是最小的答案。
判断合法的过程如下,
对于一个想要判断状态的x而言,如果他是合法的,那么每一行至少有一个数字k使得x | k == x。
直接暴力扫描,判断每行一个是否有1个这样的数,如果每行至少存在一个则欲判断的x合法。
时间复杂度分析
枚举答案29 * n * m
极限算力为500 * 200 * 200 = 20000000(2e7)
参考代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MOD = 1e9 + 7;
const int N = 210;
int a[N],b[N],s[N][N];
int main() {
freopen("in.txt", "r", stdin);
int n, m;
cin >> n >> m;
for (int i = 1; i <= n; i++) cin >> a[i];
for (int i = 1; i <= m; i++) cin >> b[i];
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
s[i][j] = a[i] & b[j];
for (int k = 0; k <= (1 << 9); k++) { // 枚举所有答案的可能性
int cnt = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if ((s[i][j] | k )== k) { // 如果每行存在一个数字与答案按位或等于答案,说明答案合法
cnt++;
break;
}
}
}
if (cnt == n) {
cout << k << endl;
break;
}
}
return 0;
}