标签:assert 最大 can 步骤 ase ++i print 导致 题解
题意:一个n行m列的矩阵,找一对可能相同的i,j,使得这两行中,设bk为每列对应元素aik,ajk的最大值,使得b序列的的最小值最大。
题解:二分这个值,然后转化成验证其是否成立。
为了减少check的次数,先进行一次离散化,大概可以减少10次check(应该),优化了1/3常数。应该还可以找每行的最小值的最大值作为二分的L。
check里面,对每行计算一个可行向量,当两行的可行向量的或为全1时,则这两行为题目所要的解。
注意若一直check失败最后要补check一次L来真正更新答案,这里被hack了。因为这种二分是必定有解的所以忽略了最后check(L)的步骤,可能这种对低级题目的掌控全局的自满导致了我的FST吧,还好不是区域赛不然就惊喜30分钟了。以后二分到达边界之后把两个值都check一遍,确定一定会有解的话就把这种自满加在assert里面吧。
int a[300005][8];
int vis[1 << 8];
int b[2400005], btop;
int ansi, ansj;
int n, m;
bool check(int mid) {
memset(vis, 0, sizeof(vis));
for(int i = 1; i <= n; ++i) {
int cur = 0;
for(int j = 0; j < m; ++j)
cur = (cur << 1) | (a[i][j] >= mid);
vis[cur] = i;
}
int all1 = (1 << m) - 1;
for(int i = all1; i; --i) {
if(!vis[i])
continue;
for(int j = 0; j < m; ++j) {
if((i >> j) & 1)
vis[i ^ (1 << j)] = vis[i];
}
}
for(int i = 0; i < (1 << m); ++i) {
if(!vis[i])
continue;
int w = all1 ^ i;
if(vis[w]) {
ansi = vis[i];
ansj = vis[w];
return true;
}
}
return false;
}
void bs() {
int L = 1, R = btop;
while(true) {
int mid = (L + R) >> 1;
if(mid == L) {
if(check(R))
return;
else {
assert(check(L));
return;
}
}
if(check(mid))
L = mid;
else
R = mid - 1;
}
}
void test_case() {
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; ++i) {
for(int j = 0; j < m; ++j) {
read(a[i][j]);
b[++btop] = a[i][j];
}
}
sort(b + 1, b + 1 + btop);
btop = unique(b + 1, b + 1 + btop) - (b + 1);
for(int i = 1; i <= n; ++i) {
for(int j = 0; j < m; ++j)
a[i][j] = lower_bound(b + 1, b + 1 + btop, a[i][j]) - b;
}
bs();
printf("%d %d\n", ansi, ansj);
}
Educational Codeforces Round 80 (Rated for Div. 2)
标签:assert 最大 can 步骤 ase ++i print 导致 题解
原文地址:https://www.cnblogs.com/KisekiPurin2019/p/12199252.html