二分 + 前缀和 - Monitor - CodeForces 846D

二分 + 前缀和 - Monitor - CodeForces 846D

题意:

给 定 一 个 n × m 的 矩 阵 , 其 中 有 q 个 点 是 坏 掉 的 , 给定一个n×m的矩阵,其中有q个点是坏掉的, n×mq

当 整 个 矩 阵 中 存 在 某 个 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, qxi,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 1n,m500,1kmin(n,m),0qnm,1xin,1yim,0ti109


分析:

求 时 间 的 最 小 值 , 而 时 间 是 满 足 单 调 性 的 , 故 我 们 可 以 二 分 答 案 。 求时间的最小值,而时间是满足单调性的,故我们可以二分答案。

如何check?

首 先 我 们 对 q 个 点 , 按 照 时 间 顺 序 从 小 到 大 排 序 , 首先我们对q个点,按照时间顺序从小到大排序, q

对 于 每 一 个 时 间 m i d , 我 们 用 二 维 数 组 a , 将 所 有 在 m i d 时 间 以 内 损 坏 的 点 上 累 加 1 , 对于每一个时间mid,我们用二维数组a,将所有在mid时间以内损坏的点上累加1, midamid1

然 后 对 数 组 a 求 一 遍 前 缀 和 , 然后对数组a求一遍前缀和, a

最 后 全 图 枚 举 k × k 的 子 矩 阵 , 查 询 子 矩 阵 中 损 坏 点 的 数 量 , 若 数 量 等 于 k × k , 则 说 明 m i d 可 行 。 最后全图枚举k×k的子矩阵,查询子矩阵中损坏点的数量,若数量等于k×k,则说明mid可行。 k×kk×kmid

二分的边界:

左 端 点 l = 0 是 可 能 取 到 的 , 左端点l=0是可能取到的, l=0

右 端 点 r 应 当 取 q 个 点 中 的 最 大 时 间 t n , 再 加 1 , 即 r = t n + 1 右端点r应当取q个点中的最大时间t_{n},再加1,即r=t_{n}+1 rqtn1r=tn+1

因 为 无 解 的 情 况 下 , l 最 终 会 增 加 到 r 的 初 始 值 , 因为无解的情况下,l最终会增加到r的初始值, lr

+ 1 是 为 了 区 分 无 解 的 情 况 , 因 答 案 是 可 能 取 到 t n 的 。 +1是为了区分无解的情况,因答案是可能取到t_n的。 +1tn

时间复杂度: 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;
}

你可能感兴趣的:(前缀和,二分)