T1:新的世界(neworld)
在一个
N
N
N 行
M
M
M列的网格中,第
i
i
i 行
j
j
j 列的格子有一个可变的 “亮度”
L
i
,
j
Li,j
Li,j(初始时都为 0)和一个固定的 “不透光度”
A
i
j
Aij
Aij。现在在
c
c
c 列放入一个亮度为
l
l
l的光源,NEWorld 游戏引擎会根据以下逻辑,让光源逐步 “照亮” 附近的方格:先将光源所在方格的亮度
L
r
c
Lrc
Lrc 赋值为
l
l
l。而对于
i
i
i 行
j
j
j 列一个不是光源的方格,它的亮度由
A
i
j
Aij
Aij和四周方格的亮度所确定
定义
F
(
i
,
j
)
=
max
(
L
i
−
1
,
j
,
L
i
+
1
,
j
,
L
i
,
j
−
1
,
L
i
,
j
+
1
,
A
i
j
)
−
A
i
j
F(i,j)=\max(Li−1,j,Li+1,j,Li,j−1,Li,j+1,Aij)−Aij
F(i,j)=max(Li−1,j,Li+1,j,Li,j−1,Li,j+1,Aij)−Aij(此处当
1
≤
i
′
≤
N
1≤i′≤N
1≤i′≤N 不成立或
1
≤
j
′
≤
M
1≤j′≤M
1≤j′≤M 不成立时,
L
i
′
j
′
Li′j′
Li′j′被看作是 0),我们称方格
(
i
,
j
)
(i,j)
(i,j) 的亮度
L
i
j
Lij
Lij 是 “有效” 的,当且仅当
L
i
j
=
F
(
i
,
j
)
Lij=F(i,j)
Lij=F(i,j)。显然初始时所有亮度都是 “有效” 的,而放入光源后则可能存在亮度 “无效” 的方格
现在引擎会循环执行操作,每一步找出当前所有亮度 “无效”(不包括光源)的方格中,行数
i
i
i 最小的那一个(如果有多个行数
i
i
i 最小的,就选择其中列数
j
j
j 最小的方格),然后计算
F
(
i
,
j
)
F(i,j)
F(i,j) 的值,将其赋值给
L
i
j
Lij
Lij。操作会不停地执行,直到所有亮度都 “有效” 为止(请参考样例,循环一定会在有限步操作后结束)。请问最后
q
q
q 列的方格亮度值
L
p
q
Lpq
Lpq 是多少?
注:
max
(
a
,
b
,
c
,
d
,
e
)
\max(a,b,c,d,e)
max(a,b,c,d,e) 表示取
a
,
b
,
c
,
d
,
e
a,b,c,d,e
a,b,c,d,e 中最大的值。
由
f
(
i
,
j
)
f(i,j)
f(i,j)的定义发现,
(
i
,
j
)
(i,j)
(i,j)只会被它周围
l
(
i
,
j
)
l(i,j)
l(i,j)最大的更改,所以从
(
i
,
j
)
(i,j)
(i,j)最小的更新简直就是废话
那么就只需要从
l
(
r
,
c
)
l(r,c)
l(r,c)跑最短路就可以了
网格图竟然没有卡SPFA,看来出题人是没有去NOI2018啊(虽然我写的也是SPFA)
T2:邻面合并(merging)
给定一个
N
×
M
N×M
N×M 的网格,每个格子上写有 0 或 1。现在用一些长方形覆盖其中写有 1 的格子,长方形的每条边都要与坐标轴平行。要求:每个写着 1 的格子都要被覆盖,长方形不可以重叠(重复绘制也多少会增加性能开销),也不能覆盖到任何一个写着 0 的格子(不然绘制结果就不正确了)请问最少需要多少长方形?
考场没想到怎么表示状压的状态和转移,打了个贪心竟然有
60
60
60%
orzsz
因为
m
<
=
8
m<=8
m<=8,所以考虑状压
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示第
i
i
i行状态为
j
j
j的最小长方形个数,
j
j
j的第
k
k
k位表示
k
k
k这个位置和上一个位置是否在一个长方形里
显然
f
[
i
]
[
j
]
=
f
[
i
−
1
]
[
k
]
+
j
f[i][j]=f[i-1][k]+j
f[i][j]=f[i−1][k]+j和
k
k
k不同的划分的长方形个数,被动转移即可
T3:光线追踪(raytracing)
考虑一个二维平面,摄像机在(0,0) 的位置,初始时平面上没有障碍物。现在执行 Q 次操作,操作有两种(假设这是第 i 次操作,1≤i≤Q):
1、给定 x0,y0,x1,y1(x0<x1,y0<y1),创建一个每条边与坐标轴平行的长方形障碍物,包含所有满足 x0≤x≤x1 且 y0≤y≤y1 的点 (x,y)(如果这个区域的某一部分已经存在障碍,则直接覆盖掉它,具体请看样例)。这个障碍物的编号为
2、给定向量 (x,y),会有一个动点从摄像机所在的 (0,0) 位置出发,以(x,y) 所指的方向前进,直到碰到第一个障碍物为止
对于第 2 种操作,输出最先碰到的障碍物的编号。若不会碰到任何障碍物,输出 0。
观察可以发现,对答案有影响的只有四边形的两条边
(
x
0
,
y
0
)
(
x
0
,
y
1
)
(x0,y0)(x0,y1)
(x0,y0)(x0,y1)和
(
x
0
,
y
0
)
(
x
1
,
y
0
)
(x0,y0)(x1,y0)
(x0,y0)(x1,y0)那么就考虑分别维护这两条边
开两棵线段树,分别存储更新这两条边影响的斜率
发现斜率是double型,没办法作为下标(虽然map可以,但是没法存线段树,而且时间过不去),那么就只能离散了(STL有离散三件套,sort,lower_bound,unique超级好用,而且省代码)
查询是得出的两条线段比较一下先碰到谁就可以了
线段树的维护有一些骚操作,更新时只要修改
[
l
,
r
]
[l,r]
[l,r]这个区间的值并且不用向下传递,(听说传递会TLE),查询的时候需要查询到底并且带着查询经过的区间的最小值就可以了
算几的细节一如既往的多,调得心态爆炸