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,那麼則說明可以達到要求。這樣便滿足時間複雜度限制

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