码迷,mamicode.com
首页 > 其他好文 > 详细

Educational Codeforces Round 80 (Rated for Div. 2)

时间:2020-01-16 00:47:26      阅读:62      评论:0      收藏:0      [点我收藏+]

标签:assert   最大   can   步骤   ase   ++i   print   导致   题解   

D - Minimax Problem

题意:一个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

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!