标签:tar 有序 long bit const href 要求 namespace cos
一般对于不容易正向求解的题,我们往往可以枚举答案并进行check,而对于具有单调性的答案或其映射来说,我们可以二分答案并进行check。
例题1:
codeforces 1288 D - Minimax Problem (传送门)
题意:
给定n行 长为m的序列;
找出任意两行序列,使得 两行序列 所有 两个相同索引的最大值 的最小值最大;
分析:
这道题朴素做法是O(n^2) ,但想在规定时间复杂度正向推出此题答案是非常不容易的;
我们可以考虑枚举 最大的最小值,再用check函数加以检验,
设当前枚举的答案为x,
对于比x小的数,令其为0,否则令其为1,最后判断两个序列对应的01串的相或的结果是否为 全1,就能判断这个x是否可能成立(本来 答案是5 ,而x是3,但是相或也能得到 全1,虽然x可能不是题目要求的bi,但是由于要求解最值,所以check成功的最大的x一定是bi),而我们则是要找到这个最大的可能;
显然,x是否可能成立是具有单调性的,所以可以用二分答案;
注意,题目的m最大为8,而01排列最多就只有 2^8种,我们可以枚举01排列 进行check,而不是O(n^2)枚举所有序列。
代码:
#include<bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<int,int> pii; const int N=1e6+5; const int inf=0x3f3f3f3f; const int mod=1e9+7; const double eps=1e-6; const long double pi=acos(-1.0L); #define ls (i<<1) #define rs (i<<1|1) #define fi first #define se second #define pb push_back #define mk make_pair #define mem(a,b) memset(a,b,sizeof(a)) LL read() { LL x=0,t=1; char ch; while(!isdigit(ch=getchar())) if(ch==‘-‘) t=-1; while(isdigit(ch)){ x=10*x+ch-‘0‘; ch=getchar(); } return x*t; } int lim,n,m,ansl,ansr;//lim是全1 int a[N][10],vis[305]; int judge(int x) { mem(vis,0); for(int i=1;i<=n;i++) { int t=0; for(int j=1;j<=m;j++) if(a[i][j]>=x) t|=1<<(j-1);//标记所有01排列 vis[t]=i; } for(int i=0;i<=lim;i++) for(int j=i;j<=lim;j++) if((i|j)==lim&&vis[i]&&vis[j]) { ansl=vis[i]; ansr=vis[j]; return 1; } return 0; } int main() { n=read(),m=read(); lim=(1<<m)-1; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) a[i][j]=read(); int l=0,r=1e9; ansl=1,ansr=1; while(l<=r) { int mid=(l+r)>>1; if(judge(mid)) l=mid+1; else r=mid-1; } printf("%d %d\n",ansl,ansr); return 0; }
标签:tar 有序 long bit const href 要求 namespace cos
原文地址:https://www.cnblogs.com/DeepJay/p/12225769.html