CF1288D-Minimax Problem-二分+二进制状态压缩

Description

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 min k = 1 m b k \min_{k=1}^m b_k 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 min k = 1 m b k \min_{k=1}^m b_k is maximum possible. If there are multiple answers, print any of them.

Sample 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

Sample Output

1 5

核心思想:

第一步:
二分枚举v = min k = 1 m b k \min_{k=1}^m b_k

第二步:
对于枚举出的v值,判断它是否可取:
每个序列的最大长度为8,用二进制数表示每个序列中哪些数是不小于v的
vis[i]=k,表示状态为i的序列可以是第k个序列。
如果(i|j)==(1<<m)-1,则状态i和状态j的组合满足条件,vis[i]和vis[j]就是答案。

详见代码!

代码如下:

#include<cstdio>
#include<iostream>
using namespace std;
typedef long long ll;
const int N=3e5+20,M=10;
//数组a存原数据,vis从状态映射序列号,w是二进制位权 
int n,m,a[N][M],vis[1<<M],w[M],ans1,ans2;
bool fun(int v)
{
	int en=1<<m;
	//初始化vis 
	for(int i=0;i<en;i++)
		vis[i]=-1;
	//获得vis 
	for(int i=1;i<=n;i++)
	{
		int t=0;
		for(int j=1;j<=m;j++)
			if(a[i][j]>=v)
				t+=w[j];
		vis[t]=i;
	}
	//两重for循环遍历序列号会超时,遍历状态即可 
	for(int i=0;i<en;i++)
		for(int j=i;j<en;j++)
			if(vis[i]!=-1&&vis[j]!=-1&&(i|j)==en-1)
			{
				ans1=vis[i],ans2=vis[j];
				return 1;
			}
	return 0;
}
int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			scanf("%d",&a[i][j]);
	//初始化位权 
	w[1]=1;
	for(int i=2;i<M;i++)
		w[i]=w[i-1]<<1;
	//二分 
	int l=0,r=1e9+10;
	while(l<=r)
	{
		int mid=(l+r)>>1;
		if(fun(mid)) l=mid+1;
		else r=mid-1;
	}
	cout<<ans1<<' '<<ans2<<endl;
	return 0;
}
发布了144 篇原创文章 · 获赞 135 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/Nothing_but_Fight/article/details/103985836