题目传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=5085
这道题我们可以先二分答案,然后转化为判定是否有四角权值>=mid的矩形。
我们可以发现,若4个点可以构成矩形,那么这四个点一定两两在同一行,同一列。
于是我们可以把每一行的合法点处理出来,在里面枚举点对。若有一个点对出现了两次,那么就说明在上面的某一行的相同列有两个合法点,即能构成矩形。
因为找到两对相同的合法点对就可以反回结果,而合法点对的规模是$ O(m^2) $的,因此总时间复杂度$ O(m^2log(n)) $。
· (然而我因为读入写错tle了好几发。。。qwq)
代码:
#include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<ctime> #include<iostream> #include<algorithm> #include<queue> #include<vector> #include<map> #define ll long long #define ull unsigned long long #define max(a,b) (a>b?a:b) #define min(a,b) (a<b?a:b) #define lowbit(x) (x& -x) #define mod 10000007 #define inf 0x3f3f3f3f #define eps 1e-10 #define maxn 1010 inline char nc(){ static char buf[100000],*p1=buf,*p2=buf; return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++; } inline ll read(){ll tmp=0; char c=nc(),f=1; for(;c<'0'||'9'<c;c=nc())if(c=='-')f=-1; for(;'0'<=c&&c<='9';c=nc())tmp=(tmp<<3)+(tmp<<1)+c-'0'; return tmp*f;} inline ll power(ll a,ll b){ll ans=1; for(;b;b>>=1){if(b&1)ans=ans*a%mod; a=a*a%mod;} return ans;} inline ll gcd(ll a,ll b){return b?gcd(b,a%b):a;} inline void swap(int &a,int &b){int tmp=a; a=b; b=tmp;} using namespace std; int a[maxn][maxn],vis[maxn][maxn]; int x[maxn]; int n,m; int check(int mid) { memset(vis,0,sizeof(vis)); for(int i=1;i<=n;i++){ int tot=0; for(int j=1;j<=m;j++) if(a[i][j]>=mid)x[++tot]=j; for(int j=1;j<tot;j++) for(int k=j+1;k<=tot;k++) if(vis[x[j]][x[k]])return 1; else vis[x[j]][x[k]]=1; } return 0; } int main() { n=read(); m=read(); int l=inf,r=-inf; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) a[i][j]=read(),l=min(l,a[i][j]),r=max(r,a[i][j]); while(l<r){ int mid=(l+r+1)>>1; if(check(mid))l=mid; else r=mid-1; } printf("%d ",l); }
Tips:听说找到权值最大的前4n个点直接爆枚就行了?然而我不会证。