做题记录整理二分3 P3933. Chtholly Nota Seniorious(2022/9/15)

P3933. Chtholly Nota Seniorious

珂朵莉666
是一个非常抽象的二分,首先需要看懂它那个不能两次拐弯意思就是

一个长成这样的东西,用一条像是楼梯一样的线把它划分成两个部分,想到这个之后还需要想到二分最大值和最小值

接着就是如何判定,这个其实就是这道题的难点,首先是用一种类似模拟的办法扫一遍矩阵,看看是否合法,如果合法就可以直接返回,如果不合法则需要进行旋转90°,然后再判断,直到转了一圈或者合法位置。
这个感觉确实比较难想到。

#include<bits/stdc++.h>
#define for1(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
int n;
int a[6][3001][3001];
int m,n2,m2;
bool jl[5005][5005];
int zt;
int mx=-1e9,mi=1e9;
void zhuan(int s,int t) {
	for1(i,1,n)
	for1(j,1,m)
	a[t][j][n - i + 1] = a[s][i][j];
	swap(m ,n);
}

bool check(int x) {
	int p = m;
	memset(jl, 0, sizeof(jl));
	for1(i,1,n)
	    for1(j,1,p)
	        if(a[zt][i][j] + x < mx) {
	        	p = j - 1;
	        	break;
	       } 
	       else jl[i][j] = true;
	for(int i = n; i; i--)
		for(int j=m; j; j--)
			if(jl[i][j]) break;
			else if(a[zt][i][j] - x > mi)
				return false;
	return true;
}
bool rcheck(int mid) {
	if(check(mid)) return true;
	swap(n, m);
	zt=(zt+1)%4;
	if(check(mid)) return true;
	swap(n, m);
	zt=(zt+1)%4;
	if(check(mid)) return true;
	swap(n, m);
	zt=(zt+1)%4;
	if(check(mid)) return true;
	swap(n, m);
	zt=(zt+1)%4;
	return false;
}
int main() {
	int l=0,r=-1,ans=0;
	cin>>n>>m;
	for1(i,1,n)
	for1(j,1,m)
	scanf("%d",&a[0][i][j]),
	      mx=max(mx,a[0][i][j]),
	      mi=min(mi,a[0][i][j]);
	zhuan(0,1);
	zhuan(1,2);
	zhuan(2,3);
	zt=3;
	r=mx-mi;
	while(r>=l) {
		double mid=(l+r)/2;
		if(rcheck(mid))
			ans=mid,r=mid-1;
		else l=mid+1;
	}
	printf("%d",ans);
	return 0;
}
posted @ 2022-09-15 17:00  yyx525jia  阅读(43)  评论(0)    收藏  举报