洛谷

说这是一道单调队列好题,但是我并不是用单调队列做的诶。

如果往最暴力的方向去想,肯定是\(n^3\)的\(dp\)了。

\(f[i][j][k]\)代表当前正方形的左上角定点是\((i,j)\),边长是\(k\)的正方形的最佳答案。

转移方程很简单,但是你一定会妥妥的\(\texttt{TLE}\)。

那么我们怎么做呢?

往倍增的方向去想,设\(f[i][j][k]\)表示左上角为\((i,j)\),边长为\(2^j\)的正方形的最佳答案。

那么状态就这么转移:

\[mx[i][j]=max(mx[i][j],max(mx[i+(1<<k)][j+(1<<k)],max(mx[i+(1<<k)][j],mx[i][j+(1<<k)])));
\]

\[mn[i][j]=min(mn[i][j],min(mn[i+(1<<k)][j+(1<<k)],min(mn[i+(1<<k)][j],mn[i][j+(1<<k)])));
\]

很简单的转移方程,不过复杂度肯定比不上单调队列的做法了。

显然复杂度\(O(n^2~log(n))\)。

代码:

#include <bits/stdc++.h>
using namespace std; const int N=1001;
int a,b,n,t[N][N];
int mx[N][N],mn[N][N],ans=2000000000,tmp; int main()
{
ios::sync_with_stdio(false);
cin>>a>>b>>n;
for (int i=0;i<a;++i)
for (int j=0;j<b;++j)
cin>>t[i][j],mn[i][j]=mx[i][j]=t[i][j];
while ((1<<(tmp+1))<=n) ++tmp;
for (int k=0;k<tmp;++k)
for (int i=0;i+(1<<k)<a;++i)
for (int j=0;j+(1<<k)<b;++j) {
mx[i][j]=max(mx[i][j],max(mx[i+(1<<k)][j+(1<<k)],max(mx[i+(1<<k)][j],mx[i][j+(1<<k)])));
mn[i][j]=min(mn[i][j],min(mn[i+(1<<k)][j+(1<<k)],min(mn[i+(1<<k)][j],mn[i][j+(1<<k)])));
}
for (int i=0;i<=a-n;++i)
for (int j=0;j<=b-n;++j) {
int MX=max(mx[i][j],max(mx[i+n-(1<<tmp)][j+n-(1<<tmp)],max(mx[i+n-(1<<tmp)][j],mx[i][j+n-(1<<tmp)])));
int MN=min(mn[i][j],min(mn[i+n-(1<<tmp)][j+n-(1<<tmp)],min(mn[i+n-(1<<tmp)][j],mn[i][j+n-(1<<tmp)])));
ans=min(MX-MN,ans);
}
cout<<ans;
return 0;
}
05-11 22:52