Py&hyh想脱单
Py&hyh想脱单
Description
总所周知,,py和hyh有十分浓烈的脱单意愿,但是非常不幸,在一个风和日丽的下午,他们穿越到一个没有妹子的世界,他必须回答一个问题才能回到本来的世界,这个问题是给出一个nm的矩阵,然后有q次操作,每一个操作,给出xi,yi,ti,表示在ti时刻摧毁(xi,yi)这个格子,然后他们要求出一个最早时刻,出现至少一个kk的矩阵被毁坏,注意:一个kk矩阵被毁坏的意思是某一个kk的矩阵中的每一个格子都被摧毁过一次或一次以上。聪明的acmer能帮他们回答这个问题吗(如果没人能ac这个题,就代表他们两个没有脱单的可能了哦)
Input
Input:采用多组输入第一行输入n,m,k,q,(1 ≤ n, m ≤ 500, 1 ≤ k ≤ min(n, m), 1 ≤ q ≤ n·m)分别代表nm的矩阵,kk的矩阵,和q次操作接下来q行每一行输入xi,yi,ti(1 ≤ xi ≤ n, 1 ≤ yi ≤ m, 0 ≤ t ≤ 1e6),代表,在ti这个时刻,xi,yi这个位置会被摧毁
Output
Out:输出一行,代表最早时刻出现至少一个k*k的矩阵被毁坏如果永远不存在这一个时刻,输出-1
Sample Input 1
2 3 2 5 2 1 8 2 2 8 1 2 1 1 3 4 2 3 2
Sample Output 1
8
Sample Input 2
3 3 2 5 1 2 2 2 2 1 2 3 5 3 2 10 2 1 100
Sample Output 2
-1
题目求的是出现至少一个k*k的矩阵被毁坏的最早时刻,可以想到时间越长,轰炸次数也是越多的,然后出现k*k的矩阵被毁坏的几率也是越大的,因此可以看出这是符合单调性的,所以可以用二分枚举时间mid,判断mid时间是否满足,若满足往前面时间找满足条件的更小的时间,若不满足则往后找。我感觉这题判断轰炸之后,是否存在1个k*k的矩阵才是难点,做法是mp【i】[j],1表示当前格子被轰炸了,0表示没有被轰炸,然后用sum[i][j]记录每个格子对应的左上方向(感觉更前缀和很相似,左上方向可以理解为是1<=列数<=j,1<=行数<=i这个范围内)被轰炸的格子数(也就是mp[I][J]为1的格子的数量),然后暴力枚举整个地图里k*k的矩阵,对一个k*k的矩阵用之前求的sum[][]数组求该矩阵内被轰炸的格子的数量,若等于k*k说明当前枚举的这个矩阵就是满足条件的矩阵。
#include<bits/stdc++.h>
using namespace std;
#define maxn 505
struct node
{
int t,x,y;
}boom[maxn*maxn];
int mp[maxn][maxn],sum[maxn][maxn];
int n,m,k,q;
bool cmp(const node&a,const node&b)
{
return a.t<b.t;
}
int query(int xa,int ya,int xb,int yb)
{
return sum[xb][yb]-sum[xa-1][yb]-sum[xb][ya-1]+sum[xa-1][ya-1];
}
bool check(int t)
{
for(int i=0;i<=n+1;i++)
for(int j=0;j<=m+1;j++)
mp[i][j]=sum[i][j]=0;
for(int i=1;i<=q;i++)
{
if(boom[i].t<=t)
mp[boom[i].x][boom[i].y]=1;
else
break;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
sum[i][j]=mp[i][j]+sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1];
}
for(int i=1;i<=n-k+1;i++)
for(int j=1;j<=m-k+1;j++)
{
int x=i,y=j,xx=i+k-1,yy=j+k-1;
if((k*k)==query(x,y,xx,yy))
return true;
}
return false;
}
int main()
{
std::ios::sync_with_stdio(false);
while(cin>>n>>m>>k>>q)
{
if(n==0&&m==0&&k==0&&q==0)
break;
for(int i=1;i<=q;i++)
{
cin>>boom[i].x>>boom[i].y>>boom[i].t;
}
sort(boom+1,boom+q+1,cmp);
int ans=-1;
int low=0,up=1000000+10,mid;
while(low<=up)
{
mid=(low+up)/2;
if(check(mid))
{
ans=mid;
up=mid-1;
}
else
low=mid+1;
}
cout<<ans<<endl;
}
return 0;
}