B4222 [常州市赛 2023] 积木题解
dongrunxuan · · 题解
B4222 [常州市赛 2023] 积木 题解
看到题解区均为二位前缀和的做法,这里提供二维 ST 表做法。
思路
首先肯定考虑二分。问题转化为求是否存在范围为
注意到这里是判断区间最小值是否大于定值,考虑使用二维 ST 表维护,注意不同于一维,二维的判断需四个值进行维护。
最后输出的值为取走的方块数,所以应输出
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=1e3+5;
int n,m,sum;
int lg[maxn];
int st[25][maxn][maxn];
int minm(int x,int y,int aa,int bb)
{
int res=min(aa,bb);
res=min(res,y);
res=min(res,x);
return res;
}
int calc(int x,int y,int len)
{
int sz=lg[len];
return minm(st[sz][x][y],st[sz][x+len-(1<<sz)][y],st[sz][x][y+len-(1<<sz)],st[sz][x+len-(1<<sz)][y+len-(1<<sz)]);
}
bool check(int x)
{
for(int i=1;i<=n-x;i++)
{
for(int j=1;j<=m-x;j++)
{
if(calc(i,j,x)>=x)
{
return 1;
}
}
}
return 0;
}
signed main()
{
cin>>n>>m;
for(int i=2;i<=n;i++) lg[i]=lg[i>>1]+1;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
cin>>st[0][i][j];
sum+=st[0][i][j];
}
}
int mx=lg[min(n,m)];
for(int k=1;k<=mx;k++)
{
for(int i=1;i+(1<<k)-1<=n;i++)
{
for(int j=1;j+(1<<k)-1<=m;j++)
{
st[k][i][j]=minm(st[k-1][i][j],st[k-1][i+(1<<k-1)][j],st[k-1][i][j+(1<<k-1)],st[k-1][i+(1<<k-1)][j+(1<<k-1)]);
}
}
}
int l=1,r=min(n,m);
int ans=1;
while(l<=r)
{
int mid=(l+r)/2;
if(check(mid)) ans=mid,l=mid+1;
else r=mid-1;
}
cout<<sum-ans*ans*ans;
return 0;
}