洛谷 P2216 [HAOI2007]理想正方形

洛谷

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

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

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

转移方程很简单,但是你一定会妥妥的( exttt{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;
}
原文地址:https://www.cnblogs.com/fushao2yyj/p/9609255.html