题意:
给你 n n n个长度为 m m m的数组,选出两个来,让他们每一位取 m a x max max构成新数组 b b b,让后最大化 b b b的最小值。
思路:
看到
m
=
8
m=8
m=8,也就是每个数组长度为
m
m
m,很容易想到状压。由于要最大化最小值,我们不妨二分这个最小值,让后将
n
n
n个数组状压成一个二进制,
>
=
m
i
d
>=mid
>=mid的位置为
1
1
1,否则为
0
0
0。这个时候我们只需要找出两个数使其取或后
[
0
,
m
−
1
]
[0,m-1]
[0,m−1]的每一位都是
1
1
1即可。
我们发现只需要记录一下当前状态对应的编号,让后
2
8
∗
2
8
2^{8}*2^{8}
28∗28枚举状态,让后判断
(
i
∣
j
)
=
=
(
1
<
<
m
)
−
1
(i|j)==(1<<m)-1
(i∣j)==(1<<m)−1即可。
复杂度
O
(
m
a
x
(
n
m
,
2
2
m
)
∗
l
o
g
(
1
e
9
)
)
O(max(nm,2^{2m})*log(1e9))
O(max(nm,22m)∗log(1e9))
如果
m
m
m很大怎么办?有没有更好的方法呢?当然是有的。
假设我们知道了状态
110101
110101
110101,那么我们只需要看一下是否存在
001010
001010
001010即可。而这个状态有可能是某个状态的子集,我们不能对于每数都将其子集暴力的加入,这样复杂度会爆掉的,看到大佬有一个好的方法来递推求子集。我们从
(
1
<
<
m
)
−
1
(1<<m)-1
(1<<m)−1开始,记为
n
o
w
now
now,让后遍历
[
0
,
m
−
1
]
[0,m-1]
[0,m−1],记为
j
j
j,看一下
n
o
w
∣
(
1
<
<
j
)
now|(1<<j)
now∣(1<<j)是否存在,存在的话就说明他是
n
o
w
∣
(
1
<
<
j
)
now|(1<<j)
now∣(1<<j)的一个子集,就直接继承
n
o
w
∣
(
1
<
<
j
)
now|(1<<j)
now∣(1<<j)的信息即可。这样递推的复杂度为
2
m
∗
m
2^m*m
2m∗m,显然更加的优秀。
复杂度 O ( m a x ( n m , 2 m ∗ m ) ∗ l o g ( 1 e 9 ) ) O(max(nm,2^{m}*m)*log(1e9)) O(max(nm,2m∗m)∗log(1e9))
//#pragma GCC optimize(2)
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#include<ctime>
#include<cstdlib>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define pb push_back
#define mk make_pair
#define Mid (tr[u].l+tr[u].r>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define db puts("---")
using namespace std;
//void rd_cre() { freopen("d://dp//data.txt","w",stdout); srand(time(NULL)); }
//void rd_ac() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//AC.txt","w",stdout); }
//void rd_wa() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//WA.txt","w",stdout); }
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;
const int N=1000010,mod=1e9+7,INF=0x3f3f3f3f;
const double eps=1e-6;
int n,m;
int a[N][10];
int id[1010],ans1,ans2;
bool flag;
bool check(int mid)
{
memset(id,0,sizeof(id));
for(int i=0;i<n;i++)
{
int now=0;
for(int j=0;j<m;j++)
if(a[i][j]>=mid) now+=(1<<j);
id[now]=i+1;
}
int tot=(1<<m);
for(int i=tot-1;i>=0;i--)
for(int j=0;j<m;j++)
if(id[i|(1<<j)])
id[i]=id[i|(1<<j)];
for(int i=tot-1;i>=0;i--)
if(id[i]&&id[i^(tot-1)])
{
ans1=id[i];
ans2=id[i^(tot-1)];
return true;
}
return false;
}
int main()
{
// ios::sync_with_stdio(false);
// cin.tie(0);
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++) for(int j=0;j<m;j++) scanf("%d",&a[i][j]);
int l=0,r=1e9,ans;
while(l<=r)
{
int mid=l+r>>1;
if(check(mid)) l=mid+1;
else r=mid-1;
}
printf("%d %d\n",ans1,ans2);
return 0;
}
/*
*/
复杂度 O ( m a x ( n m , 2 2 m ) ∗ l o g ( 1 e 9 ) ) O(max(nm,2^{2m})*log(1e9)) O(max(nm,22m)∗log(1e9))
//#pragma GCC optimize(2)
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#include<ctime>
#include<cstdlib>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define pb push_back
#define mk make_pair
#define Mid (tr[u].l+tr[u].r>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define db puts("---")
using namespace std;
//void rd_cre() { freopen("d://dp//data.txt","w",stdout); srand(time(NULL)); }
//void rd_ac() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//AC.txt","w",stdout); }
//void rd_wa() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//WA.txt","w",stdout); }
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;
const int N=1000010,mod=1e9+7,INF=0x3f3f3f3f;
const double eps=1e-6;
int n,m;
int a[N][10];
int id[1010],ans1,ans2;
bool flag;
bool check(int mid)
{
memset(id,0,sizeof(id));
for(int i=0;i<n;i++)
{
int now=0;
for(int j=0;j<m;j++)
if(a[i][j]>=mid) now+=(1<<j);
id[now]=i+1;
}
for(int i=0;i<(1<<m);i++)
for(int j=0;j<(1<<m);j++)
if(id[i]&&id[j]&&(i|j)==((1<<m)-1))
{
ans1=id[i],ans2=id[j];
return true;
}
return false;
}
int main()
{
// ios::sync_with_stdio(false);
// cin.tie(0);
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++) for(int j=0;j<m;j++) scanf("%d",&a[i][j]);
int l=0,r=1e9,ans;
while(l<=r)
{
int mid=l+r>>1;
if(check(mid)) l=mid+1;
else r=mid-1;
}
printf("%d %d\n",ans1,ans2);
return 0;
}
/*
*/