YunYan

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

题目大意:n*m的矩阵中,找到两行数,可以形成两个一维数组,数组1的位置i和数组2的位置i去最大构成新数组b的元素b[i],最终目的要使数组b中最小的数尽可能的大

题解:

  m的范围是(1,8),比较小,我们用二分答案加按位与或来做,维护一个二维数组,当arr[i][j]>=x时,记为1,否则记为0。所以每一行最多有8个数,也就是最多会有pow(2,8)=256种答案。然后对这些数保留与或就行了,时间复杂度logx(max)*(n*m)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll INF=1e9+7;
const ll N=3E5+7;
ll arr[N][10];
ll mark[N][10];
ll goal=0;
ll cnt[N];
ll mp[N];
ll n,m;
ll ans1=0,ans2=0;
bool check(ll x){
    memset(mark,0,sizeof(mark));
    memset(mp,0,sizeof mp);
    for(ll i=1;i<=n;i++){
        for(ll j=1;j<=m;j++){
            if(arr[i][j]>=x) mark[i][j]=1;
            else mark[i][j]=0;
        }
    }
    ll pos=0;
    for(ll i=1;i<=n;i++){
        ll c=0;
        for(ll j=1;j<=m;j++){
            if(mark[i][j]){
                c+=1<<(j-1);
            }
        }
        if(!mp[c]){
            mp[c]=i;
            cnt[pos++]=c;
        }
    }
    if(pos==1){
        if(cnt[0]==goal){
            ans1=mp[goal];
            ans2=mp[goal];
            return 1;
        }
        else return 0;
    }
    for(ll i=0;i<pos;i++)
        for(ll j=i+1;j<pos;j++){
            if((cnt[i]|cnt[j])==goal) {
                ans1=mp[cnt[i]];
                ans2=mp[cnt[j]];
                return 1;
            }
        }
    return 0;

}
int  main(){
    ios::sync_with_stdio(false );
    cin>>n>>m;
    ll left=INF,right=0;
    for(ll i=1;i<=n;i++){
        for(ll j=1;j<=m;j++){
            cin>>arr[i][j];
            left=min(left,arr[i][j]);
            right=max(right,arr[i][j]);
        }
    }
    for(ll i=0;i<m;i++) goal+=1<<i;
    int ansa=-1,ansb=-1;
    while(left<=right){
        ll mid=(left+right)/2;
        if(check(mid)){
            left=mid+1;
            ansa=ans1;
            ansb=ans2;
        }
        else right=mid-1;
    }
    cout<<ansa<<" "<<ansb<<endl;
    return 0;
}

 

posted on 2020-01-24 22:49  Target--fly  阅读(206)  评论(0编辑  收藏  举报