题目背景

大样例下发链接: ​​https://pan.baidu.com/s/1nuVpRS1​​ 密码: sfxg

こんなにも、たくさんの幸せをあの人に分けてもらった

だから、きっと

今の、私は

谁が何と言おうと

世界一、幸せな女の子だ

noip模拟赛 Chtholly Nota Seniorious_最小值

题目描述

——“假如……我是说假如喔。

万一我再过五天就会死,你能不能对我温柔一点?”

巨大的六号兽五天后将袭击浮游大陆。

无数次计算得到的残酷数据表明,只有圣剑瑟尼欧尼斯的适格精灵——珂朵莉·诺塔·瑟尼欧尼斯(Chtholly Nota Seniorious)开启妖精乡之门,才可以以生命为代价守住浮游岛。

noip模拟赛 Chtholly Nota Seniorious_最小值_02

“至少,我也希望自己不用消失,也想让别人记住。我也想留下羁绊啊。”

留给妖精少女珂朵莉的时间似乎已经不多了。

noip模拟赛 Chtholly Nota Seniorious_最小值_03

年轻的二等技官,妖精仓库的管理员,世界上最后一个人类——威廉·克梅修,数百年前曾经是一名准勇者,掌握着成为一名勇者所需要的所有知识。

大战在即,调整圣剑的状态成为了一项重要的任务。

瑟尼欧里斯(セニオリス)
圣剑的其中之一,在现存的遗迹兵装中,拥有最强大的力量。
拥有非常特殊的资质,只有极少一部分的人才能使用。
由四十一个护符组成。能将所有事物包含不死者都回归「死亡」。

威廉需要调整圣剑的状态,因此他将瑟尼欧尼斯拆分护符,组成了一个nn行mm列的矩阵。

每一个护符都有自己的魔力值。现在为了测试圣剑,你需要将这些护符分成 A,B两部分。

要求如下:


  1. 圣剑的所有护符,恰好都属于两部分中的一部分。
  2. 每个部分内部的方块之间,可以通过上下左右相互到达,而且每个内部的方块之间互相到达,最多允许拐一次弯。

例如

AAAAA  AAAAA  AAAAA
AABAA  BaAAA  AAABB
ABBBA  BBAAA  AAABB
AABAA  BaAAA  ABBBB
AAAAA  AAAAA  BBBBB

  (1)     (2)     (3)

其中(1)(2)是不允许的分法,(3)是允许的分法。在(2)中,a属于A区域,这两个a元素之间互相到达,没有办法最多只拐一次弯。

现在要问,所有合法的分法中,A区域的极差与B区域的极差 中间较大的一个的 最小值 是多少?

好心而可爱的在一旁默默观察奈芙莲悄悄地告诉你,极差就是区域内最大值减去最小值。

noip模拟赛 Chtholly Nota Seniorious_#include_04

夜晚的风吹拂着,68号岛上的景色竟与地上的森林无异。转念又想,黄金妖精本身就是与森林之中出现,成长,消亡的神秘存在啊。

时间不早了,早上训练中落败的珂朵莉即将回来了。您要尽快和威廉一起调整好圣剑,千万不能迟哟。

noip模拟赛 Chtholly Nota Seniorious_最小值_05

noip模拟赛 Chtholly Nota Seniorious_#include_06

分析:把图分成两个部分其实就相当于画一条单调的线:noip模拟赛 Chtholly Nota Seniorious_i++_07,为了使得极差最小,最大值和最小值肯定不在同一部分,先假设最大值在蓝色部分,最小值在红色部分。要求最大极差最小,可以想到二分答案,判断的时候一行一行的判断,看蓝色部分最多能够从右往左延伸到哪里,接下来判断其它的红色部分能否满足条件就行了.如果答案是k,蓝色区域都≥x-k,红色区域都≤y+k,x是最大值,y是最小值.

      每次二分求出来的只是一种情况,红蓝对调需要翻折一次,分割线单调上升或下降也需要翻折一次,也就是说把图形旋转4次求得最小值才是答案.



#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int inf = 0x7fffffff;

int n, m, a[2010][2010], ans = inf, maxx = -inf, minn = inf;

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

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

bool check(int x)
{
int p = 0;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
if (a[i][j] < maxx - x)
p = max(p, j);
for (int j = 1; j <= m; j++)
if (minn + x < a[i][j])
if (j <= p)
return false;
}
return true;
}

int solve()
{
int l = 0, r = maxx - minn, res = 0;
while (l <= r)
{
int mid = (l + r) >> 1;
if (check(mid))
{
res = mid;
r = mid - 1;
}
else
l = mid + 1;
}
return res;
}

int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
{
scanf("%d", &a[i][j]);
minn = min(minn, a[i][j]);
maxx = max(maxx, a[i][j]);
}
ans = min(ans, solve());
turnl();
ans = min(ans, solve());
turnn();
ans = min(ans, solve());
turnl();
ans = min(ans, solve());
printf("%d\n", ans);

return 0;
}