cf Educational Codeforces Round 80 D. Minimax Problem

原题:

D. Minimax Problem
time limit per test
5 seconds
memory limit per test
512 megabytes
input
standard input
output
standard output

给你n个序列,a1,a2,...,ana_1,a_2,...,a_n,每个序列包含m个整数。假设第x个序列的第y个元素可以表示为ax,ya_{x,y}。现在需要找到两个序列aia_iaja_j,这里i可以等于j。并且,需要构造一个新的序列b,长度为m,对于序列b中的每个数bkb_k,要求bk=max(ai,k,aj,k)b_k=max(a_{i,k},a_{j,k}),现在要求你选择这样两个序列i和j,使得序列b中最小的的数最大。其中m∈[1,8],n属于[1,3*10^5]

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

代码:

#include<bits/stdc++.h>
using namespace std;
 
typedef long long ll;
typedef pair<int,int> pii;
 
const int maxn = 3e5 + 1;
const int maxm = 8 + 1;
const ll mod = 1e9 + 7;
 
int n,m;
int a[maxn][maxm];
int line[1<<maxm];
int x,y;
 
bool solve(int mid)
{
    memset(line,-1,sizeof(line));
    for(int i=1;i<=n;i++)
    {
        int tmp = 0;
        for(int j=1;j<=m;j++)
        {
            if(a[i][j]>=mid)
                tmp |=(1<<(j-1));
        }
        
        if(tmp == (1<<m)-1)
        {
            x=y=i;
            return true;
        }
        
        line[tmp] = i;
    }
 
    for(int i=0;i<(1<<m);i++)
    {
        for(int j=0;j<(1<<m); j++)
        {
            if(line[i] != -1 && line[j] != -1 && (i|j) == (1<<m)-1)
            {
                x = line[i];
                y = line[j];
                return true;
            }
        }
    }
    return false;
}
int main()
{
    ios::sync_with_stdio(false);
    int inf = 0;
    while(cin>>n>>m)
    {
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                cin>>a[i][j];
                inf = max(inf,a[i][j]);
            }
        }
        x = y = n;
        int L = 0, R = inf + 2;
        while(R - L > 1)
        {
            int mid = (L + R) >> 1;
            if(solve(mid))
                L = mid;
            else
                R = mid;
        }
        cout<<x<<" "<<y<<endl;
    }
    return 0;
}

解答:

找最小值最大的这种问题基本上都是二分,遇到数据范围小于20的,基本上都可以往位运算上面想一想 -_-||
此题目也不例外,如果想到用二分找极大值极小,那么问题解决了一半,首先二分枚举可以找到的最小值mid,然后通过一个函数solve(mid)判断当前最小值是否可以达到,如果可以达到,那么把二分查找的区间扩大。

现在关键在于如何快速的判断mid这个数是否可以在满足题目规则要求的情况下达到。
假如选择了两行,aia_iaja_j,两个序列的长度是m,要选择两个序列中对应下标较大值组成新的序列,且满足新序列中最小值是mid。 那么,序列aia_i中比mid小的数字,对应到序列aja_j序列中的数字,一定要大于等于mid,例如。
ai=[5,1,0,3,4]a_i=[5,1,0,3,4] aj=[3,4,5,2,1]a_j=[3,4,5,2,1] mid = 3
序列aia_i中比mid小的数字为[1,0],那么对应到aja_j序列中下标的数字一定要大于等于3才能满足要求,如aja_j中对应下标的数字是[4,5],取最大值后得到的结果为[5,4,5,3,4]。

那么,可以使用位运算来进行判断一个序列中如果数字大于等于mid,数字对应位数可以设置为1,小于mid的可以设置为0,那么两个序列可以用两个整数表示,如果这两个数通过取或运算后全部为1,那么则说明可以达到要求。这样便满足时间复杂度限制

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章