题意:
给 定 一 个 n × m 的 矩 阵 , 其 中 有 q 个 点 是 坏 掉 的 , 给定一个n×m的矩阵,其中有q个点是坏掉的, 给定一个n×m的矩阵,其中有q个点是坏掉的,
当 整 个 矩 阵 中 存 在 某 个 k × k 的 子 矩 阵 中 的 点 都 坏 了 , 那 么 整 个 矩 阵 就 会 损 坏 。 当整个矩阵中存在某个k×k的子矩阵中的点都坏了,那么整个矩阵就会损坏。 当整个矩阵中存在某个k×k的子矩阵中的点都坏了,那么整个矩阵就会损坏。
q 个 点 按 照 一 定 的 时 间 顺 序 损 坏 , q个点按照一定的时间顺序损坏, q个点按照一定的时间顺序损坏,
判 断 最 早 在 何 时 , 整 个 矩 阵 会 损 坏 , 即 出 现 k × k 个 子 矩 阵 内 的 点 均 损 坏 的 情 况 。 判断最早在何时,整个矩阵会损坏,即出现k×k个子矩阵内的点均损坏的情况。 判断最早在何时,整个矩阵会损坏,即出现k×k个子矩阵内的点均损坏的情况。
若 不 存 在 整 个 矩 阵 损 坏 的 情 况 , 输 出 − 1 。 若不存在整个矩阵损坏的情况,输出-1。 若不存在整个矩阵损坏的情况,输出−1。
输入:
首 行 输 入 四 个 正 整 数 , n , m , k , q 首行输入四个正整数,n,m,k,q 首行输入四个正整数,n,m,k,q
接 着 q 行 , 每 行 包 括 三 个 正 整 数 x i , y i , t i , 接着q行,每行包括三个正整数x_i,y_i,t_i, 接着q行,每行包括三个正整数xi,yi,ti,
表 示 ( x i , y i ) 处 的 点 在 t i 时 刻 损 坏 。 表示(x_i,y_i)处的点在t_i时刻损坏。 表示(xi,yi)处的点在ti时刻损坏。
输出:
一 个 正 整 数 , 表 示 答 案 。 一个正整数,表示答案。 一个正整数,表示答案。
Examples
Input
2 3 2 5
2 1 8
2 2 8
1 2 1
1 3 4
2 3 2
Output
8
Input
3 3 2 5
1 2 2
2 2 1
2 3 5
3 2 10
2 1 100
Output
-1
数据范围:
1 ≤ n , m ≤ 500 , 1 ≤ k ≤ m i n ( n , m ) , 0 ≤ q ≤ n ⋅ m , 1 ≤ x i ≤ n , 1 ≤ y i ≤ m , 0 ≤ t i ≤ 1 0 9 1 ≤ n, m ≤ 500, 1 ≤ k ≤ min(n, m), 0 ≤ q ≤ n·m,1 ≤ x_i ≤ n, 1 ≤ y_i ≤ m, 0 ≤ t _i ≤ 10^9 1 ≤ n, m ≤ 500, 1 ≤ k ≤ min(n, m), 0 ≤ q ≤ n⋅m,1 ≤ xi ≤ n, 1 ≤ yi ≤ m, 0 ≤ ti ≤ 109
分析:
求 时 间 的 最 小 值 , 而 时 间 是 满 足 单 调 性 的 , 故 我 们 可 以 二 分 答 案 。 求时间的最小值,而时间是满足单调性的,故我们可以二分答案。 求时间的最小值,而时间是满足单调性的,故我们可以二分答案。
如何check?
首 先 我 们 对 q 个 点 , 按 照 时 间 顺 序 从 小 到 大 排 序 , 首先我们对q个点,按照时间顺序从小到大排序, 首先我们对q个点,按照时间顺序从小到大排序,
对 于 每 一 个 时 间 m i d , 我 们 用 二 维 数 组 a , 将 所 有 在 m i d 时 间 以 内 损 坏 的 点 上 累 加 1 , 对于每一个时间mid,我们用二维数组a,将所有在mid时间以内损坏的点上累加1, 对于每一个时间mid,我们用二维数组a,将所有在mid时间以内损坏的点上累加1,
然 后 对 数 组 a 求 一 遍 前 缀 和 , 然后对数组a求一遍前缀和, 然后对数组a求一遍前缀和,
最 后 全 图 枚 举 k × k 的 子 矩 阵 , 查 询 子 矩 阵 中 损 坏 点 的 数 量 , 若 数 量 等 于 k × k , 则 说 明 m i d 可 行 。 最后全图枚举k×k的子矩阵,查询子矩阵中损坏点的数量,若数量等于k×k,则说明mid可行。 最后全图枚举k×k的子矩阵,查询子矩阵中损坏点的数量,若数量等于k×k,则说明mid可行。
二分的边界:
左 端 点 l = 0 是 可 能 取 到 的 , 左端点l=0是可能取到的, 左端点l=0是可能取到的,
右 端 点 r 应 当 取 q 个 点 中 的 最 大 时 间 t n , 再 加 1 , 即 r = t n + 1 右端点r应当取q个点中的最大时间t_{n},再加1,即r=t_{n}+1 右端点r应当取q个点中的最大时间tn,再加1,即r=tn+1
因 为 无 解 的 情 况 下 , l 最 终 会 增 加 到 r 的 初 始 值 , 因为无解的情况下,l最终会增加到r的初始值, 因为无解的情况下,l最终会增加到r的初始值,
+ 1 是 为 了 区 分 无 解 的 情 况 , 因 答 案 是 可 能 取 到 t n 的 。 +1是为了区分无解的情况,因答案是可能取到t_n的。 +1是为了区分无解的情况,因答案是可能取到tn的。
时间复杂度: O ( n m l o g t ) O(nmlogt) O(nmlogt)
代码:
#include
#include
#include
#include
#define ll long long
using namespace std;
const int N=510;
struct node
{
int x,y,t;
bool operator < (const node s) const
{
return t<s.t;
}
}T[N*N];
int n,m,k,q;
int sum[N][N];
bool check(int mid)
{
static int a[N][N];
memset(a,0,sizeof a);
memset(sum,0,sizeof sum);
int idx=0;
while(idx<=q && T[idx].t<=mid)
{
a[T[idx].x][T[idx].y]=1;
++idx;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j];
for(int i=k;i<=n;i++)
for(int j=k;j<=m;j++)
{
int x=i-k+1,y=j-k+1;
if(sum[i][j]-sum[x-1][j]-sum[i][y-1]+sum[x-1][y-1]==k*k)
return true;
}
return false;
}
int main()
{
scanf("%d%d%d%d",&n,&m,&k,&q);
for(int i=0;i<q;i++) scanf("%d%d%d",&T[i].x,&T[i].y,&T[i].t);
sort(T,T+q);
int l=0,r=T[q-1].t+1;
while(l<r)
{
int mid=l+r>>1;
if(check(mid)) r=mid;
else l=mid+1;
}
if(l>T[q-1].t) puts("-1");
else printf("%d\n",l);
return 0;
}