题目大意: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; }