Educational Codeforces Round 80 (Rated for Div. 2) D. Minimax Problem

D. Minimax Problem
题意:给n组长度为m的数组,n<=3*1e5,m<=8,可以合并两个数组,合并后的数组为b[i]=max(a[x][i],a[y][i]).求合并方法使合并两个数组后的那个数组中的值的最小值最大。
解析:首先最小值最大很容易想到二分,然后可以二分最小值为mid,然后问题转化成是否可以选择两个数组使最小值大于等于mid,因为m<=8,所以就可以状态压缩,大于等于mid的话就是1,小于mid就为0,然后判断两个数组合并后的最小值是否大于等于mid就是两个数组状态压缩之后的两个数或操作之后是否全为1,当然如果n个数组暴力的话复杂度是n的平方,肯定爆了,于是可以把n个数组状态压缩后的值映射成vis[1<<m]数组,这样就可以暴力找了因为vis数组的大小为1<<m,即最大2的8次方,所以2的八次方的平方为2的16次方不会爆,这个地方应该注意,因为思维惯性,想n的平方的复杂度肯定没法处理所以n的平方的方法一定不行,可是却忽略了映射之后的2的8次方的值很小,只有256,其平方也很小,是可以接受的时间复杂度,最后注意一下check函数初始化即可。

#include<iostream>
#include<cstdio>
using namespace std;
const int MAX_N=301000;
int a[MAX_N][10];
int ans1,ans2,n,m;
int b[MAX_N],vis[1010];
int fin;
bool check(int x){
 //cout<<x<<" x \n";
 int i,j;
 for(i=0;i<(1<<m);i++)
 vis[i]=0;
 for(i=1;i<=n;i++)
 b[i]=0;
 for(i=1;i<=n;i++){
  for(j=0;j<m;j++){
   if(a[i][j]>=x)
   b[i]+=(1<<j);
  }
  //cout<<b[i]<<" b[i]\n";
  vis[b[i]]=i;
 }
 for(i=0;i<(1<<m);i++){
  if(!vis[i])
  continue;
  for(j=0;j<(1<<m);j++){
   if(vis[j]&&(i|j)==fin){
    ans1=vis[i];
    ans2=vis[j]; 
    return true;
   }
  }
 }
 return false;
}
int main(void){
 int i,j;
 scanf("%d%d",&n,&m);
 for(i=1;i<=n;i++){
  for(j=0;j<m;j++){
   scanf("%d",&a[i][j]);
  }
 }
 fin=(1<<m)-1;
 int l=0,r=1e9,mid=(l+r)>>1;
 int ans=-1;
 while(l<=r){
  if(check(mid)){
   ans=mid;
   l=mid+1;
  }
  else{
   r=mid-1;
  }
  mid=(l+r)>>1;
 }
 //cout<<mid<<"\n";
 check(mid);
 printf("%d %d\n",ans1,ans2);
 return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值