洛谷 P2216 [HAOI2007]理想正方形

洛谷

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

如果往最暴力的方向去想,肯定是\(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;
}
posted @ 2018-09-08 15:06  fuyan0101  阅读(143)  评论(0编辑  收藏  举报