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

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

题意:

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

k × k 当整个矩阵中存在某个k×k的子矩阵中的点都坏了,那么整个矩阵就会损坏。

q q个点按照一定的时间顺序损坏,

k × k 判断最早在何时,整个矩阵会损坏,即出现k×k个子矩阵内的点均损坏的情况。

1 若不存在整个矩阵损坏的情况,输出-1。

输入:

n , m , k , q 首行输入四个正整数,n,m,k,q

q x i , y i , t i 接着q行,每行包括三个正整数x_i,y_i,t_i,

( x i , y i ) t i 表示(x_i,y_i)处的点在t_i时刻损坏。

输出:

一个正整数,表示答案。

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


分析:

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

如何check?

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

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

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

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

二分的边界:

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

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

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

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

时间复杂度: O ( n m l o g t ) O(nmlogt)

代码:

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

#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;
}

猜你喜欢

转载自blog.csdn.net/njuptACMcxk/article/details/107572138