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;
}
posted @ 2021-06-10 11:45  acmloser  阅读(31)  评论(0编辑  收藏  举报