Educational Codeforces Round 80 (Rated for Div. 2) D. Minimax Problem

题目链接:https://codeforces.com/contest/1288/problem/D

 

题目大意:

  有n个数组,每个数组有m个数字,选择其中两个数组会形成一个新数组b,方法是,对于每一个位置,挑选两个数组中该位较大的数字。求使b数组中最小值最大的是哪两行

 

题目思路:

  n高达3e5,暴力直接歇逼。看到最小值最大马上就想到了二分,但是一秒钟就把自己否了。。还是不够自信,看到只有600+过题人数就虚了。。后来还是看了大佬的,感觉思路确实很简单但是非常巧妙。由于m非常小,最多8。这说明了什么?这说明状态非常少!直接二分答案,然后每一行用二进制表示,如果这一位>=x(x就是被二分的值),就说明这一行无论跟谁在一起,这一位都有这行打包票救住。由于状态非常非常少,所以直接n^2枚举状态,要求只有两个,一个是这两个状态或起来是全集,也就是每一列都有人能保,还有一个就是这个状态有行满足,这个就需要id数组,记录每个状态对应的行,然后输出即可。
  以后遇到数据范围特别小的就要想到状态枚举,也不要因为看到状态枚举就觉得很难,可能非常简单!

 

以下是代码:

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
#define ll long long
const int MAXN = 3e5+5;
const int MOD = 1e9+7;
int a[MAXN][10],n,m;
int x,y,id[1000];
bool check(int mid){
    memset(id,0,sizeof(id));
    rep(i,1,n){
        int temp=0;
        rep(j,1,m){
            if(a[i][j]>=mid){
                temp|=(1<<(j-1));
            }
        }
        id[temp]=i;
    }
    int endd=(1<<m)-1;
    rep(i,0,endd){
        rep(j,0,endd){
            if((i|j)==endd&&id[i]&&id[j]){
                x=id[i],y=id[j];
                return 1;
            }
        }
    }
    return 0;
}
int main(){
    scanf("%d%d",&n,&m);
    rep(i,1,n){
        rep(j,1,m)scanf("%d",&a[i][j]);
    }
    int l=0,r=1e9+7;
    while(l<=r){
        int mid=(l+r)>>1;
        if(check(mid)){
            l=mid+1;
        }
        else r=mid-1;
    }
    cout<<x<<" "<<y<<endl;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值