Monitor CodeForces - 846D
原题链接
考察:前缀和+二分
错误思路:
求每个\(k*k\)矩阵的最大值,没想出来,还以为是dp
思路:
将最大值问题转换为个数问题,求在ans时间内,\(k*k\)矩阵和 = k*k是否为true.这里二分+前缀和(树状数组)解决.
时间复杂度O(\(n*m*log_2 q\))
Code
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 510;
int n,m,k,q,tr[N][N];
struct Node{
int x,y,t;
bool operator<(Node s){
return this->t<s.t;
}
}node[N*N];
int lowbit(int z)
{
return z&-z;
}
void insert(int x,int y,int v)
{
for(int i=x;i<=n;i+=lowbit(i))
for(int j=y;j<=m;j+=lowbit(j))
tr[i][j]+=v;
}
int query(int a,int b)
{
int res = 0;
for(int i=a;i;i-=lowbit(i))
for(int j=b;j;j-=lowbit(j))
res+=tr[i][j];
return res;
}
bool check(int mid)//在node[mid].t时间内的二维前缀s==k*k的个数
{
memset(tr,0,sizeof tr);
for(int i=1;i<=mid;i++)
insert(node[i].x,node[i].y,1);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
int a = i+k-1,b=j+k-1;
if(a>n||b>m) break;
int s = query(a,b)-query(a,j-1)-query(i-1,b)+query(i-1,j-1);
if(s==k*k) return 1;
}
return 0;
}
int main()
{
scanf("%d%d%d%d",&n,&m,&k,&q);
for(int i=1;i<=q;i++)
{
int x,y,t; scanf("%d%d%d",&x,&y,&t);
node[i] = {x,y,t};
}
sort(node+1,node+q+1);
int l=1,r = q+1;
bool ok = 0;
while(l<r)
{
int mid = l+r>>1;
if(check(mid)) r = mid,ok =1;
else l = mid+1;
}
if(ok) printf("%d\n",node[r].t);
else puts("-1");
return 0;
}