1. 程式人生 > >JZOJ5938. 【NOIP2018模擬10.30】分離計劃

JZOJ5938. 【NOIP2018模擬10.30】分離計劃

Description

眾所周知,小Z擁有者足以毀滅世界的力量,可惜他不能控制這份力量,小J和小Z的關係十分親密,一天小J預感到了小Z體內的力量將要爆發。 這次爆發的力量比以往都要強大,以至於將小Z分為了兩個整體,彼此之間靠著萬有引力互相靠近,一旦融合,世界將不復存在。 為了拯救世界,小J決定打造一個容器G,將小Z的兩個部分分別裝在容器G的一個部分,用以控制小Z 容器由n*m個魔法水晶組成,他們組成了一個n行m列的矩陣,每個魔法水晶都有自己的能量值,容器需要 被分為兩個部分,使得每個魔法水晶都屬於且僅屬於一個部分,並且任何一個魔法水晶都可以在矩陣中只經過和自己屬於同一部分的魔法水晶由一條最多改變一次方向的路徑抵達另一個和他處於同一部分的魔法水晶 例如: AAAAA. .AAAAA. .AAAAA AABAA. .BAAAA. .AAABB ABBBA. .BBAAA. .AAABB AABAA. .BAAAA. .ABBBB AAAAA. .AAAAA. .BBBBB

…(1)…(2)…(3)… 使用.隔開(辣雞的題面格式化) 其中12是不合法的容器,3是合法的容器 對於每一個部分,他的不穩定性是屬於這個部分的所有魔法水晶能量值的極差(最大-最小) 對於整個容器,不穩定性是兩部分不穩定性中的最大值 為了知道自己能不能拯救世界,不白白浪費時間,小J想知道整個容器的最小的不穩定值

Data Constraint

對於15%的資料 n,m≤10 對於另15%的資料,n,m中有一個為1 對於55%的資料 n,m≤200(包括最初的15%) 對於所有資料,n,m≤2000,1≤能量值≤1e9

題解

先理解一下題目給出的兩個區域分界線是怎麼樣子的, 顯然是一條折線,而且每行每列的分界線就只有一條。 顯然不可以直接列舉分界線, 考慮二分一個極差, 將整個圖分為最小值所在部分,以及最大值所在部分, 然後就暴力判斷是否可行,這裡可以做到O(nm)。

code

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#define N 2003
#define G getchar
using namespace std;
char ch;
void read(int &n)
{
	n=0;
	ch=G();
	while((ch<'0' || ch>'9') && ch!='-')ch=G();
	int w=1;
	if(ch=='-')w=-1,ch=G();
	while('0'<=ch && ch<='9')n=(n<<3)+(n<<1)+ch-'0',ch=G();
	n*=w;
}

int max(int a,int b){return a>b?a:b;}
int min(int a,int b){return a<b?a:b;}

int n,m,mx,mi,a[N][N],b[N][N],x,ans;
int s1[N][N],s2[N][N],l,r,mid;
bool pd;

int find(int i,int x)
{
	int l=1,r=m+1,mid;
	for(;l<r;)
	{
		mid=(l+r)>>1;
		if(s2[i][mid]>x)l=mid+1;else r=mid;
	}
	return l;
}

void work(int n,int m)
{
	for(int i=1;i<=n;i++)
	{
		s1[i][0]=mx;
		for(int j=1;j<=m;j++)
			s1[i][j]=min(s1[i][j-1],a[i][j]);
	}
	for(int i=1;i<=n;i++)
	{
		s2[i][m+1]=mi;
		for(int j=m;j;j--)
			s2[i][j]=max(s2[i][j+1],a[i][j]);
	}
	for(l=0,r=mx-mi;l<r;)
	{
		mid=(l+r)>>1;x=pd=1;
		for(int i=1;i<=n;i++)
		{
			x=max(x,find(i,mi+mid));
			if(x==m+1 || mx-s1[i][x-1]>mid)
			{
				pd=0;
				break;
			}
		}
		if(pd)r=mid;else l=mid+1;
	}
	ans=min(ans,l);
}

int main()
{
	freopen("separate.in","r",stdin);
	freopen("separate.out","w",stdout);
	
	read(n);read(m);ans=mi=2147483647;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			read(a[i][j]),mx=max(mx,a[i][j]),mi=min(mi,a[i][j]);
	
	work(n,m);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			b[j][n-i+1]=a[i][j];
	swap(n,m);memcpy(a,b,sizeof(a));
	work(n,m);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			b[j][n-i+1]=a[i][j];
	swap(n,m);memcpy(a,b,sizeof(a));
	work(n,m);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			b[j][n-i+1]=a[i][j];
	swap(n,m);memcpy(a,b,sizeof(a));
	work(n,m);
	printf("%d",ans);
	
	return 0;
}