1. 程式人生 > >jzoj5938. 【NOIP2018模擬10.30】分離計劃(二分)

jzoj5938. 【NOIP2018模擬10.30】分離計劃(二分)

5938. 【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想知道整個容器的最小的不穩定值

Input
第一行兩個數n,m代表魔法水晶組成的矩陣大小
隨後n行,每行m個整數表示魔法水晶的能量值

Output
一行一個整數,表示最小的不穩定值

Sample Input
4 4
1 12 6 11
11 4 2 14
10 1 9 20
4 17 13 10

Sample Output
11

樣例說明
BBBA
BBBA
BBBA
BAAA
B極差12-1=11 A極差20-10=10,不穩定值為11,分法不唯一

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

分析:二分答案,假設最大值在藍色區域,最小值在紅色
區域,考慮如何檢驗,對於每一行找到紅色區域的最大範
圍,再在藍色區域中檢驗極差,旋轉 4 遍

程式碼

#include <cstdio>
#include <algorithm>
#define N 3000
using namespace std;

int a[N][N],b[N][N],c[N][N],d[N][N];
int n,m,mx,mn;

void change()
{
	for (int i = 1; i <= n; i++)
    	for (int j = 1; j <= m / 2; j++)
      		swap(a[i][j], a[i][m - j + 1]);
}

bool check(int x)
{
	int las = m + 1;
	for (int i = 1; i <= n; i++)
	{
		int t = 0;
		for (int j = 1; j <= min(las, m); j++)
			if (mx - a[i][j] <= x) t = max(t, j);
				else break;
		las = t;
		for (int j = t + 1; j <= m; j++)
			if (a[i][j] - mn > x) return false;
	}
	return true;
}

int find()
{
	int l = 0, r = mx - mn + 1, ans = 0;
	while (l <= r)
	{
		int mid = (l + r) / 2;
		if (check(mid)) ans = mid, r = mid - 1;
			else l = mid + 1;
	}
	change();
	l = 0, r = mx - mn + 1;
	while (l <= r)
	{
		int mid = (l + r) / 2;
		if (check(mid)) ans = min(ans, mid), r = mid - 1;
			else l = mid + 1;
	}
	for (int i = 1; i <= n / 2; i++)
      for (int j = 1; j <= m; j++)
        swap(a[i][j], a[n - i + 1][j]);
	l = 0, r = mx - mn + 1;
	while (l <= r)
	{
		int mid = (l + r) / 2;
		if (check(mid)) ans = min(ans, mid), r = mid - 1;
			else l = mid + 1;
	}
	change();
	l = 0, r = mx - mn + 1;
	while (l <= r)
	{
		int mid = (l + r) / 2;
		if (check(mid)) ans = min(ans, mid), r = mid - 1;
			else l = mid + 1;
	}
	return ans;
}

int main()
{
	freopen("data1.in","r",stdin);
//	freopen("separate.out","w",stdout);
	scanf("%d%d", &n, &m);
	mx = 0, mn = 1e9;
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
		{
			scanf("%d", &a[i][j]);
			mx = max(mx, a[i][j]);
			mn = min(mn, a[i][j]);
		}
	change();
 	printf("%d", find());
}