Chtholly Nota Seniorious
题目背景
大样例下发链接: https://pan.baidu.com/s/1nuVpRS1 密码: sfxg
こんなにも、たくさんの幸せをあの人に分けてもらった
だから、きっと
今の、私は
谁が何と言おうと
世界一、幸せな女の子だ
题目描述
——“假如……我是说假如喔。
万一我再过五天就会死,你能不能对我温柔一点?”
巨大的六号兽五天后将袭击浮游大陆。
无数次计算得到的残酷数据表明,只有圣剑瑟尼欧尼斯的适格精灵——珂朵莉·诺塔·瑟尼欧尼斯(Chtholly Nota Seniorious)开启妖精乡之门,才可以以生命为代价守住浮游岛。
“至少,我也希望自己不用消失,也想让别人记住。我也想留下羁绊啊。”
留给妖精少女珂朵莉的时间似乎已经不多了。
年轻的二等技官,妖精仓库的管理员,世界上最后一个人类——威廉·克梅修,数百年前曾经是一名准勇者,掌握着成为一名勇者所需要的所有知识。
大战在即,调整圣剑的状态成为了一项重要的任务。
瑟尼欧里斯(セニオリス)
圣剑的其中之一,在现存的遗迹兵装中,拥有最强大的力量。
拥有非常特殊的资质,只有极少一部分的人才能使用。
由四十一个护符组成。能将所有事物包含不死者都回归「死亡」。
威廉需要调整圣剑的状态,因此他将瑟尼欧尼斯拆分护符,组成了一个nn行mm列的矩阵。
每一个护符都有自己的魔力值。现在为了测试圣剑,你需要将这些护符分成 A,B两部分。
要求如下:
-
圣剑的所有护符,恰好都属于两部分中的一部分。
- 每个部分内部的方块之间,可以通过上下左右相互到达,而且每个内部的方块之间互相到达,最多允许拐一次弯。
例如
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区域的极差 中间较大的一个的 最小值 是多少?
好心而可爱的在一旁默默观察奈芙莲悄悄地告诉你,极差就是区域内最大值减去最小值。
夜晚的风吹拂着,68号岛上的景色竟与地上的森林无异。转念又想,黄金妖精本身就是与森林之中出现,成长,消亡的神秘存在啊。
时间不早了,早上训练中落败的珂朵莉即将回来了。您要尽快和威廉一起调整好圣剑,千万不能迟哟。
输入输出格式
输入格式:
第一行两个自然数n,mn,m
接下来nn行,每行mm个自然数A_{i,j}Ai,j表示权值
输出格式:
一个整数表示答案。
输入输出样例
4 4 1 12 6 11 11 4 2 14 10 1 9 20 4 17 13 10
11
说明
样例解释
1 12 6 11
11 4 2 14
10 1 9 20
4 17 13 10
分法不唯一,如图是一种合法的分法。左边部分极差12-1=11,右边一块极差20-10=10,所以答案取这两个中较大者11。没有别的分法,可以使答案更小。
数据范围与约定
测试点 | n | m |
---|---|---|
#1-2 | \le 10≤10 | \le 10≤10 |
#3-4 | 1 | \le 2000≤2000 |
#5-7 | \le 200≤200 | \le 200≤200 |
#8-10 | \le 2000≤2000 | \le 2000≤2000 |
对于所有的权值1\le A_{i,j} \le 10^91≤Ai,j≤109
我们需要按行扫这个矩阵两遍,第一遍从上往下扫,第二遍从下往上扫。
基于贪心的原则,对于每一行,我们从右往左扫。当遇到这一行第一个(最靠右的一个)满足的格子的时候停止,然后下一行从同一个位置开始往左扫。这样贪心可以保证满足条件的同时给下一行更多的选择。
把左边的部分记为A部分,右边的部分记为B部分,则扫的时候顺便维护下每一部分扫到上一行为止的最大最小值,在扫这行的过程中就判断下最大值减最小值会不会爆……
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 int a[2001][2001],premax[2001][2001],premin[2001][2001]; 7 int sufmax[2001][2001],sufmin[2001][2001],n,m,ans; 8 bool check1(int k) 9 {int i,j; 10 int lim=m,maxa=0,mina=2e9,maxb=0,minb=2e9; 11 for (i=1;i<=n;i++) 12 { 13 int flag=0; 14 for (j=lim;j>=0&&flag==0;j--) 15 { 16 if (max(max(maxa,premax[i][j])-min(mina,premin[i][j]),max(maxb,sufmax[i][j+1])-min(minb,sufmin[i][j+1]))<=k) 17 { 18 lim=j; 19 maxa=max(premax[i][j],maxa); 20 if (j+1<=m) 21 maxb=max(sufmax[i][j+1],maxb); 22 mina=min(premin[i][j],mina); 23 if (j+1<=m) 24 minb=min(sufmin[i][j+1],minb); 25 flag=1; 26 } 27 } 28 if (flag==0) return 0; 29 } 30 return 1; 31 } 32 bool check2(int k) 33 {int i,j; 34 int lim=m,maxa=0,mina=2e9,maxb=0,minb=2e9; 35 for (i=n;i>=1;i--) 36 { 37 int flag=0; 38 for (j=lim;j>=0&&flag==0;j--) 39 { 40 if (max(max(maxa,premax[i][j])-min(mina,premin[i][j]),max(maxb,sufmax[i][j+1])-min(minb,sufmin[i][j+1]))<=k) 41 { 42 lim=j; 43 maxa=max(premax[i][j],maxa); 44 if (j+1<=m) 45 maxb=max(sufmax[i][j+1],maxb); 46 mina=min(premin[i][j],mina); 47 if (j+1<=m) 48 minb=min(sufmin[i][j+1],minb); 49 flag=1; 50 } 51 } 52 if (flag==0) return 0; 53 } 54 return 1; 55 } 56 int main() 57 {int i,j; 58 cin>>n>>m; 59 for (i=1;i<=n;i++) 60 for (j=1;j<=m;j++) 61 scanf("%d",&a[i][j]); 62 for (i=1;i<=n;i++) 63 { 64 premax[i][1]=premin[i][1]=a[i][1]; 65 for (j=2;j<=m;j++) 66 { 67 premax[i][j]=max(premax[i][j-1],a[i][j]); 68 premin[i][j]=min(premin[i][j-1],a[i][j]); 69 } 70 sufmax[i][m]=sufmin[i][m]=a[i][m]; 71 for (j=m-1;j>=1;j--) 72 { 73 sufmax[i][j]=max(sufmax[i][j+1],a[i][j]); 74 sufmin[i][j]=min(sufmin[i][j+1],a[i][j]); 75 } 76 sufmin[i][m+1]=premin[i][0]=2e9; 77 } 78 int l=0;int r=1e9; 79 while (l<=r) 80 { 81 int mid=(l+r)/2; 82 if (check1(mid)||check2(mid)) ans=mid,r=mid-1; 83 else l=mid+1; 84 } 85 cout<<ans; 86 }