标签:le int ans1 Minimax CodeForces 数组 1288D pos2 pos1
题意
给 \(n\) 个数组,每个数组 \(m(1\le m\le 8)\) 个数,你需要选两个数组 \(a,b\),可以相同,使得 \(Min_{1\le i\le m}\{max(a_i,b_i)\}\) 最大。
思路
二分好题啊
一般二分题可以从题目要求上明显看出“求符合要求的最值”这个意思,而且要能证明这个问题是单调的,就是说如果要求符合要求的最小值,那么比这个最小值小的值一定不符合要求,而比这个最小值大的值一定符合要求。还有一个条件就是,反向验证这个值比正向思考这个问题要简单。
回到这道题,想想怎么验证答案。
比如说要验证 \(x\) 是否合法,就是要验证从这 \(n\) 个数组中选 \(2\) 个出来,是否两个数组对应位置上较大的数都大于等于 \(x\)。
可以对于每个数组,考虑每一位数,把大于等于 \(x\) 的那一位置为 \(1\),小于置为 \(0\),那么我们发现可以用一个二进制数来表示这个数组。而且这个二进制数很小,最大 \(2^8-1\)
那么把这个数对应的数组的编号记下来,然后看是否有两个数都表示了某个数组,并且这两个数取或为全 \(1\),即 \(2^m-1\),那么 \(x\) 合法,并且这两个数表示的数组编号也是对应满足要求的两个数组。
不知道我写的是不是足够清晰,其实看看结合代码看一下应该能明白吧
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int inf=0x3f3f3f3f;
const LL INF=0x3f3f3f3f3f3f3f3f;
const int MAXN=3e5+10;
int n,m,a[MAXN][10],mark[300],pos1,pos2,ans1,ans2;
bool check(int x){
pos1=0,pos2=0;
memset(mark,0,sizeof(mark));
for(int i=1;i<=n;i++){
int now=0;
for(int j=0;j<m;j++) now+=((a[i][j]>=x)<<j);
mark[now]=i;
}
for(int i=0;i<(1<<m);i++)
for(int j=i;j<(1<<m);j++)
if((i|j)==(1<<m)-1&&mark[i]&&mark[j])
pos1=mark[i],pos2=mark[j];
return pos1&&pos2;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=0;j<m;j++)
scanf("%d",&a[i][j]);
int l=0,r=1e9;
while(l<r){
int mid=(l+r+1)>>1;
if(check(mid)) ans1=pos1,ans2=pos2,l=mid;
else r=mid-1;
}
check(l);ans1=pos1,ans2=pos2;
printf("%d %d\n",ans1,ans2);
return 0;
}
标签:le,int,ans1,Minimax,CodeForces,数组,1288D,pos2,pos1 来源: https://www.cnblogs.com/BakaCirno/p/12220912.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。