luogu P2216 [HAOI2007]理想的正方形

题面传送门
一看到最大最小值,而且是区间,立马想到两个东西:stst和单调队列。这里介绍一种stst表的做法。
但这可是二维,我们只学过一维的。
回想一下之前的前缀和和差分,我们是怎么一维转多维的。
维恩图!
首先是建表,肯定还是拿来拼,四个小正方形拼一个大正方形。
stmaxi,j,kstmax_{i,j,k}表示以iijj为右下角端点边长为2k2^k的正方形内最大值为多少。
那么就可以拼了:stmaxi,j,k=max(stmaxi,j2k1,k1,max(stmaxi,j,k1,max(stmaxi2k1,j,k1],stmaxi2k1,j2k1,k1)))stmax_{i,j,k}=max(stmax_{i,j-2^{k-1},k-1},max(stmax_{i,j,k-1},max(stmax_{i-2^{k-1},j,k-1}],stmax_{i-2^{k-1},j-2^{k-1},k-1})))
同理,最小值亦可以拼。stmini,j,k=min(stmini,j2k1,k1,min(stmini,j,k1,min(stmini2k1,j,k1],stmini2k1,j2k1,k1)))stmin_{i,j,k}=min(stmin_{i,j-2^{k-1},k-1},min(stmin_{i,j,k-1},min(stmin_{i-2^{k-1},j,k-1}],stmin_{i-2^{k-1},j-2^{k-1},k-1})))
然后是查询,因为他这里查的是正方形,所以省了很多不必要的麻烦。正方形边长为nn那么最后一维就可以定下来了:log2(n)log^2(n)向下取整。模仿维恩图和一维stst,可以推出结论:
max(stmaxi,jq+2k,k,max(stmaxi,j,k,max(stmaxiq+2k,j,k,stmaxiq+2k,jq+2k,kmax(stmax_{i,j-q+2^k,k},max(stmax_{i,j,k},max(stmax_{i-q+2^k,j,k},stmax_{i-q+2^k,j-q+2^k,k}
同理,最小值:
min(stmini,jq+2k,k,min(stmini,j,k,min(stminiq+2k,j,k,stminiq+2k,jq+2k,kmin(stmin_{i,j-q+2^k,k},min(stmin_{i,j,k},min(stmin_{i-q+2^k,j,k},stmin_{i-q+2^k,j-q+2^k,k}
两个相减,第一,二维枚举,同时取最小值。
代码实现:

#include<cstdio>
using namespace std;
int n,m,q,stmin[1039][1039][10],stmax[1039][1039][10],ans=1e9,tot,pus,a[1039][1039];
inline int max(int a,int b) {
    return a>b?a:b;
}
inline int min(int a,int b) {
    return a<b?a:b;
}
inline void read(int &x){
    char s=getchar();x=0;
    while(s<'0'||s>'9') s=getchar();
    while(s>='0'&&s<='9') x=(x<<3)+(x<<1)+(s^48),s=getchar();
}
int main() {
    register int i,j,k;
    scanf("%d%d%d",&n,&m,&q);
    for(i=1; i<=n; i++) {
        for(j=1; j<=m; j++) read(a[i][j]),stmax[i][j][0]=stmin[i][j][0]=a[i][j];
    }
    for(k=1; (1<<k)<=q; k++) {
        for(i=1<<k; i<=n; i++) {
            for(j=1<<k; j<=m; j++) {
                stmax[i][j][k]=max(stmax[i][j-(1<<k-1)][k-1],max(stmax[i][j][k-1],max(stmax[i-(1<<k-1)][j][k-1],stmax[i-(1<<k-1)][j-(1<<k-1)][k-1])));
                stmin[i][j][k]=min(stmin[i][j-(1<<k-1)][k-1],min(stmin[i][j][k-1],min(stmin[i-(1<<k-1)][j][k-1],stmin[i-(1<<k-1)][j-(1<<k-1)][k-1])));
            }
        }
    }
    k=0;
    while((1<<k+1)<=q) k++;
    for(i=q; i<=n; i++) {
        for(j=q; j<=m; j++) {
            ans=min(ans,max(stmax[i][j-q+(1<<k)][k],max(stmax[i][j][k],max(stmax[i-q+(1<<k)][j][k],stmax[i-q+(1<<k)][j-q+(1<<k)][k])))-min(stmin[i][j-q+(1<<k)][k],min(stmin[i][j][k],min(stmin[i-q+(1<<k)][j][k],stmin[i-q+(1<<k)][j-q+(1<<k)][k]))));
        }
    }
    printf("%d",ans);
    return 0;
}
发布了90 篇原创文章 · 获赞 0 · 访问量 1844
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 精致技术 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览