Minimax Problem

You are given nn arrays a1,a2,...,ana_1, a_2, ..., a_n; each array consists of exactly m integers. We denote the y-th element of the x-th array as ax,ya_{x,y}.

You have to choose two arrays aia_i and aja_j (1i,jn1≤i,j≤n, it is possible that i=ji=j). After that, you will obtain aa new array bb consisting of m integers, such that for every k[1,m]k∈[1,m] bk=max(ai,k,aj,k)b_k=max(a_{i,k},a_{j,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 nn and mm (1n3105,1m81≤n≤3⋅10^5, 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(0ax,y109)a_{x,1}, a_{x,2}, ..., a_{x,m} (0≤a_{x,y}≤10^9).

Output
Print two integers ii and jj (1i,jn1≤i,j≤n, it is possible that i=ji=j) — the indices of the two arrays you have to choose so that the value of mink=1mbk\min \limits_{k = 1}^{m} b_k 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

mink=1mbk\min \limits_{k = 1}^{m} b_k進行二分。
設當前值爲midmid,對於矩陣中的某元素ai,ja_{i,j},如果ai,jmida_{i,j}≥mid,則矩陣ci,j=1c_{i,j}=1,否則ci,j=0c_{i,j}=0
mid=3mid=3爲例,樣例中的矩陣aa可以得到矩陣cc如下:

1 0 1 0 0
0 1 1 0 1
0 0 1 1 1
1 0 0 1 1
0 1 0 1 1
1 1 0 1 0

可以看到,矩陣cc的第1行和第5行逐列相與結果均爲1,因此對於選擇第1行和第5行得到的序列bbmink=1mbkmid\min \limits_{k = 1}^{m} b_k≥mid。函數check()check()就是尋找對於當前midmid是否存在行ii和行jj,使得矩陣cc的第ii行和第jj行逐列相與結果均爲11。由於1n31051≤n≤3⋅10^5,暴力枚舉iijj會超時,但是由於1m81≤m≤8,因此可以枚舉行ii,枚舉滿足條件的行jj,然後檢查是否存在jj即可。
值得注意的是,由於本題要輸出行號iijj,而不是輸出mink=1mbk\min \limits_{k = 1}^{m} b_k。雖然得到了正確的mink=1mbk\min \limits_{k = 1}^{m} b_k,但是由於l=rl=r跳出二分過程導致mid=mink=1mbkmid=\min \limits_{k = 1}^{m} b_k的情況沒有check()check()更新答案,因此在二分結束後還要check()check()mid=mink=1mbkmid=\min \limits_{k = 1}^{m} b_k的情況。

#include<bits/stdc++.h>

#define si(a) scanf("%d",&a)
#define sl(a) scanf("%lld",&a)
#define sd(a) scanf("%lf",&a)
#define sc(a) scahf("%c",&a);
#define ss(a) scanf("%s",a)
#define pi(a) printf("%d\n",a)
#define pl(a) printf("%lld\n",a)
#define pc(a) putchar(a)
#define ms(a) memset(a,0,sizeof(a))
#define repi(i, a, b) for(register int i=a;i<=b;++i)
#define repd(i, a, b) for(register int i=a;i>=b;--i)
#define reps(s) for(register int i=head[s];i;i=Next[i])
#define ll long long
#define ull unsigned long long
#define vi vector<int>
#define pii pair<int,int>
#define mii unordered_map<int,int>
#define msi unordered_map<string,int>
#define lowbit(x) ((x)&(-(x)))
#define ce(i, r) i==r?'\n':' '
#define pb push_back
#define fi first
#define se second
#define INF 0x3f3f3f3f
#define pr(x) cout<<#x<<": "<<x<<endl
using namespace std;

inline int qr() {
    int f = 0, fu = 1;
    char c = getchar();
    while (c < '0' || c > '9') {
        if (c == '-')fu = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9') {
        f = (f << 3) + (f << 1) + c - 48;
        c = getchar();
    }
    return f * fu;
}

const int N = 3e5 + 10, M = 10;
int a[N][M], n, m, ans1, ans2, now, sta[N];
mii num;


inline void build(int x) {
    num.clear();
    repi(i, 1, n) {
        int res = 0;
        repi(j, 0, m - 1)if (a[i][j] >= x)res += 1 << j;
        num[res] = i, sta[i] = res;
    }
}

bool dfs(int x, int u) {
    if (u == m) {
        if (num[x]) {
            ans1 = now, ans2 = num[x];
            return true;
        }
        return false;
    }
    if (!((sta[now] >> u) & 1))return dfs(x | (1 << u), u + 1);
    else {
        if (dfs(x, u + 1))return true;
        if (dfs(x ^ (1 << u), u + 1))return true;
        return false;
    }
}

inline bool check() {
    repi(i, 1, n) {
        now = i;
        if (dfs(0, 0))return true;
    }
    return false;
}

int main() {
    n = qr(), m = qr();
    int l = INF, r = 0;
    repi(i, 1, n)repi(j, 0, m - 1) {
            a[i][j] = qr();
            l = min(l, a[i][j]);
            r = max(r, a[i][j]);
        }
    while (l < r) {
        int mid = (l + r + 1) >> 1;
        build(mid);
        check() ? (l = mid) : (r = mid - 1);
    }
    build(l);
    check();
    printf("%d %d\n", ans1, ans2);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章