D.Minimax Problem
You are given n arrays a1, a2, …, an; each array consists of exactly m integers. We denote the y-th element of the x-th array as ax,y.
You have to choose two arrays ai and aj (1≤i,j≤n, it is possible that i=j). After that, you will obtain a new array b consisting of m integers, such that for every k∈[1,m] bk=max(ai,k,aj,k).
Your goal is to choose i and j so that the value of mink=1mbk is maximum possible.
Input
The first line contains two integers n and m (1≤n≤3⋅105, 1≤m≤8) — the number of arrays and the number of elements in each array, respectively.
Then n lines follow, the x-th line contains the array ax represented by m integers ax,1, ax,2, …, ax,m (0≤ax,y≤109).
Output
Print two integers i and j (1≤i,j≤n, it is possible that i=j) — the indices of the two arrays you have to choose so that the value of mink=1mbk is maximum possible. If there are multiple answers, print any of them.
Example
Input
6 5
5 0 3 1 2
1 8 9 1 3
1 2 3 4 5
9 1 0 3 7
2 3 0 6 3
6 4 1 7 0
Output
1 5
题意:
给n,m
然后给n个长度为m的数组
你可以任选两个下标i,j (1<=i<=j<=n)
他们可以构造出一个新数组b,其中bk=max(aik,ajk)
即bi为两个数组i位置上的数取max
现在要你选择两个下标i,j
满足构造出的b数组的最小值最大
输出选择的两个下标
思路:
二分:
已经告诉你是最小值最大化了,很容易想到二分
主要是check怎么写,容易想到N^2的强行check,但是显然tle
看了题解学到一手状压写法:
假设当前check(mid),因为m最大只有8
对于每个数组,每个元素如果a[i][j]>=mid,则二进制第j位为1,否则为0
然后就可以用一个状态x存下当前数组a[i],记录状态对应的下标sta[x]=i
暴力O((1<<m)^2)遍历状态for(i)for(j)
如果(i|j)==(1<<m)-1则说明存在两个数组能构造出最小值大于等于mid的数组b
记录下答案sta[i]和sta[j]
不断二分就行了,因为二分是单调的,所以答案会在check的过程中逐渐最优
code:
#include<bits/stdc++.h>
using namespace std;
const int maxm=3e5+5;
int a[maxm][10];
int sta[maxm];//(1<<8)只有256
int ansx,ansy;
int n,m;
bool check(int mid){
for(int i=0;i<(1<<m);i++){//clear
sta[i]=0;
}
for(int i=1;i<=n;i++){
int x=0;
for(int j=1;j<=m;j++){
if(a[i][j]>=mid){
x|=(1<<(j-1));
}
}
sta[x]=i;
}
for(int i=0;i<(1<<m);i++){
for(int j=i;j<(1<<m);j++){
if(sta[i]&&sta[j]){//两种状态都存在才进一步判断
if((i|j)==(1<<m)-1){//如果有可行解
ansx=sta[i];//答案更新
ansy=sta[j];
return 1;
}
}
}
}
return 0;
}
signed main(){
cin>>n>>m;
int l=1e9,r=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>a[i][j];//1e9
l=min(l,a[i][j]);
r=max(r,a[i][j]);
}
}
while(l<=r){//二分过程是单调的,check过程中答案只会更优,不用额外记录mid
int mid=(l+r)/2;
if(check(mid)){
l=mid+1;
}else{
r=mid-1;
}
}
cout<<ansx<<' '<<ansy<<endl;
return 0;
}