https://codeforces.com/contest/1288/problem/D
卧槽这题也FST了,edu round还只看罚时,,做了E也没用啊艹
这题看见最小值最大,就肯定往二分上想了,然后只要想到存在s[i] | s[j] = (1<<m)-1,就行了,那么我们先把所有s[i]存入标记数组,再把他们的子集存入标记数组,再枚举每个s[i],看他们的补集有没有被标记就行了。
#include<bits/stdc++.h>
#define maxl 300010
using namespace std;
int n,m,ans,len,mini=2e9,mx=0,ansu,ansv;
int a[maxl][9],s[maxl],mi[maxl];
int vis[maxl];
inline void prework()
{
scanf("%d%d",&n,&m);
len=1<<m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
scanf("%d",&a[i][j]);
mini=min(mini,a[i][j]);
mx=max(mx,a[i][j]);
}
}
inline bool jug(int mid)
{
for(int i=0;i<len;i++)
vis[i]=0;
for(int i=1;i<=n;i++)
{
s[i]=0;
for(int j=1;j<=m;j++)
if(a[i][j]>=mid)
s[i]|=mi[j];
vis[s[i]]=i;
}
for(int i=len-1;i>0;i--)
if(vis[i])
for(int j=1;j<=m;j++)
if(i&mi[j])
vis[i^mi[j]]=vis[i];
for(int i=1;i<=n;i++)
if(vis[(len-1)^s[i]])
{
ansu=i;ansv=vis[(len-1)^s[i]];
return true;
}
return false;
}
inline void mainwork()
{
int l=mini,r=mx,mid;
while(l+1<r)
{
mid=(l+r)>>1;
if(jug(mid))
l=mid;
else
r=mid;
}
if(jug(r))
ans=r;
else if(jug(r-1))
ans=r-1;
}
inline void print()
{
//printf("%d",ans);
printf("%d %d",ansu,ansv);
}
int main()
{
mi[1]=1;
for(int i=2;i<=8;i++)
mi[i]=mi[i-1]*2;
int t=1;
//scanf("%d",&t);
for(int i=1;i<=t;i++)
{
prework();
mainwork();
print();
}
return 0;
}