牛客多校第三场——F Planting Trees

//又是一个矩阵的问题,还要,我在网上看了一个二维ST表的做法,找不到了,而且我自己只过了百分之九十的样例https://ac.nowcoder.com/acm/contest/883/F
在这里插入图片描述
在这里插入图片描述
题意:就是求满足条件的最大矩形面积,其实就是求二维的最大值最小值,满足条件就可以,我用二维ST表过了百分之九十,网上大部分都是用单调栈做的,我先找找我之前提交的代码,呜呜呜~~~
//这个是错的,哈哈哈,超了1ms再改改,天哪

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=505;
int mm[1005];
int val[maxn][maxn];
int dpmin[maxn][maxn][9][9];
int dpmax[maxn][maxn][9][9];
void initRMQ(int n,int m)
{
    for(int i=1;i<=n;i++)
     for(int j=1;j<=m;j++)
      dpmin[i][j][0][0]=dpmax[i][j][0][0]=val[i][j];
    for(int ii=0;ii<=mm[n];ii++)
     for(int jj=0;jj<=mm[m];jj++)
     if(ii+jj)
     for(int i=1;i+(1<<ii)-1<=n;i++)
     for(int j=1;j+(1<<jj)-1<=m;j++)
     {
         if(ii)
        {
             dpmin[i][j][ii][jj]=min(dpmin[i][j][ii-1][jj],dpmin[i+(1<<(ii-1))][j][ii-1][jj]);
             dpmax[i][j][ii][jj]=max(dpmax[i][j][ii-1][jj],dpmax[i+(1<<(ii-1))][j][ii-1][jj]);
         }
         else
         {
            dpmin[i][j][ii][jj]=min(dpmin[i][j][ii][jj-1],dpmin[i][j+(1<<(jj-1))][ii][jj-1]);
            dpmax[i][j][ii][jj]=max(dpmax[i][j][ii][jj-1],dpmax[i][j+(1<<(jj-1))][ii][jj-1]);
         }
    }
 }
int rmq1(int x1,int y1,int x2,int y2)//max
{
     int k1=mm[x2-x1+1];
     int k2=mm[y2-y1+1];
     x2=x2-(1<<k1)+1;
     y2=y2-(1<<k2)+1;
     return max(max(dpmax[x1][y1][k1][k2],dpmax[x1][y2][k1][k2]),max(dpmax[x2][y1][k1][k2],dpmax[x2][y2][k1][k2]));
}
int rmq2(int x1,int y1,int x2,int y2)
{
     int k1=mm[x2-x1+1];
     int k2=mm[y2-y1+1];
     x2=x2-(1<<k1)+1;
     y2=y2-(1<<k2)+1;
    return min(min(dpmin[x1][y1][k1][k2],dpmin[x1][y2][k1][k2]),min(dpmin[x2][y1][k1][k2],dpmin[x2][y2][k1][k2]));
}
int cal(int x1,int y1,int x2,int y2)
{
    return rmq1(x1,y1,x2,y2)-rmq2(x1,y1,x2,y2);
}
void read(int &x)
{
    char c=getchar();
    x = 0;
    while(c<'0'||c>'9')
    c=getchar();
    while(c<='9'&&c>='0')
    x=x*10+c-48,c=getchar();
}
void put(int x)
{
    int num=0; char c[15];
    while(x)
    c[++num]=(x%10)+48,x/=10;
    while(num)
    putchar(c[num--]);
    putchar('\n');
}
int main()
{
    int t,n,m;
    read(t);
    mm[0]=-1;
for(int i=1;i<=1005;i++)
mm[i]=((i&(i-1))==0)?mm[i-1]+1:mm[i-1];
    while(t--)
    {
     read(n);
     read(m);
     int ans=0;
     for(int i=1;i<=n;i++)
     for(int j=1;j<=n;j++)
     read(val[i][j]);
     initRMQ(n,n);
    for(int i=1;i<=n;i++)//O(n^4)一定不行,这样没想到可以过,还是看数据吧,哈哈
      for(int j=1;j<=n;j++)
      {
         int x=j,mi1=val[i][j],mx1=val[i][j];
         while(x<=n&&mx1-mi1<=m)//从(i,j)开始的在这一行上的最远距离
         {
          ++x;
          mi1=min(mi1,val[i][x]);
          mx1=max(mx1,val[i][x]);
         }
         --x;
         ans=max(ans,x-j+1);
        for(int k=i+1;k<=n;k++)
         {
             while(x>=j&&cal(i,j,k,x)>m)
             --x;
            if((n-i+1)*(x-j+1)<=ans)
            break;
            ans=max(ans,(k-i+1)*(x-j+1));
         }
     }
     put(ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值