zoj 4738 Choir 二维RMQ+预处理

来源:互联网 发布:javascript 刷新div 编辑:程序博客网 时间:2024/06/04 15:33

题意:给定n*m的矩阵小格。每个小格都有一个数值,代表这个位置人的身高。给q个询问,每个询问给 x,y 要求在这个n*m的矩阵中找一个x*y的子矩阵(n是行m是列,x是行,y是列)这个子矩阵中除去最高的那个人。剩余人的方差。求满足x*y的子矩阵的方差最小的xy坐标,并输出方差 


首先贡献一发方差公式:


可以把它分拆成 

((x1*x1+x2*x2+.....+xn*xn) - 2*(x1+x2+..+xn)*(平均值)+n*(平均值)*(平均值))/n

想到这里的时候已经成功了一半了。所谓好的开端就是成功的一半。

现在我们转换一下问题:

我转换成了一下三个小问题:

1)求出给定的一个大矩形中的某个子矩形的和,我们希望复杂度尽量低

2)求出给定的一个大矩形中的某个子矩形的平方的和,我们希望复杂度尽量低

3)求出给定的一个大矩形中的某个子矩形的最大值,我们希望复杂度也尽量低

好了,如果能明白并写出这三个小问题的解。那么这题也就这样了。

1)可以预处理出左上角到当前i,j位置的和sum1[i][j],这样查询的时候就可以直接O(1)的查询了,对于给定的x,y,x1,y1这个矩形。那么这个矩形的值为:

sum1[x1][y1]-sum1[x-1][y1]-sum1[x1][y1-1]-sum1[x-1][y-1]

2)可以预处理出左上角到当前i,j位置的平方的和,这样查询的时候也可以直接O(1)的查询,同上。1)和2)是同一个做法。

3)2维RMQ求子矩形的最大值。

好了,代码:

//author: CHC//First Edit Time:2014-07-23 15:00#include <iostream>#include <cstdio>#include <cstring>#include <cmath>#include <set>#include <vector>#include <map>#include <queue>#include <set>#include <algorithm>using namespace std;#define MAXN 310int rec[MAXN][MAXN];int dp[MAXN][MAXN][10][10];int n,m;int summ[MAXN][MAXN];int sumn[MAXN][MAXN];int sum1[MAXN][MAXN];int sum2[MAXN][MAXN];inline int maxm(int a,int b,int c,int d){    if(a<b)a=b; if(a<c)a=c; if(a<d)a=d;    return a;}void st(){    for(int k=0;(1<<k)<=n;k++)    for(int l=0;(1<<l)<=m;l++)    for(int i=1;i+(1<<k)-1<=n;i++)    for(int j=1;j+(1<<l)-1<=m;j++)    {        if(!k&&!l){            dp[i][j][k][l]=rec[i][j];        }        else if(k==0){            dp[i][j][k][l]=max(dp[i][j][k][l-1],dp[i][j+(1<<(l-1))][k][l-1]);        }        else if(l==0){            dp[i][j][k][l]=max(dp[i][j][k-1][l],dp[i+(1<<(k-1))][j][k-1][l]);        }        else {        dp[i][j][k][l]=maxm(dp[i][j][k-1][l-1],dp[i+(1<<(k-1))][j][k-1][l-1],                            dp[i][j+(1<<(l-1))][k-1][l-1],dp[i+(1<<(k-1))][j+(1<<(l-1))][k-1][l-1]);        }    }}int rmq2dmax(int x,int y,int x1,int y1){    int k=log(x1-x+1)/log(2);    int l=log(y1-y+1)/log(2);    return maxm(dp[x][y][k][l],dp[x1-(1<<k)+1][y][k][l],                dp[x][y1-(1<<l)+1][k][l],dp[x1-(1<<k)+1][y1-(1<<l)+1][k][l]);}void pre_do(){    for(int i=1;i<=n;i++)    for(int j=1;j<=m;j++){        summ[i][j]=summ[i][j-1]+rec[i][j];        sum1[i][j]=sum1[i-1][j]+summ[i][j];        sumn[i][j]=sumn[i][j-1]+rec[i][j]*rec[i][j];        sum2[i][j]=sum2[i-1][j]+sumn[i][j];    }}int getare1(int x,int y,int x1,int y1){    return sum1[x1][y1]-sum1[x-1][y1]-sum1[x1][y-1]+sum1[x-1][y-1];}int getare2(int x,int y,int x1,int y1){    return sum2[x1][y1]-sum2[x-1][y1]-sum2[x1][y-1]+sum2[x-1][y-1];}int main(){    memset(summ,0,sizeof(summ));    memset(sum1,0,sizeof(sum1));    int cas=0;    while(~scanf("%d%d",&n,&m)){        for(int i=1;i<=n;i++)        for(int j=1;j<=m;j++)            scanf("%d",&rec[i][j]);        st();        pre_do();        int q;        scanf("%d",&q);        printf("Case %d:\n",++cas);        int nn,mm;        while(q--){            scanf("%d%d",&nn,&mm);            int posx=1,posy=1;            double fancha=-1.0;            for(int x=1;x+nn-1<=n;x++)            for(int y=1;y+mm-1<=m;y++){                int ma=rmq2dmax(x,y,x+nn-1,y+mm-1);                int a1=getare1(x,y,x+nn-1,y+mm-1)-ma;                int a2=getare2(x,y,x+nn-1,y+mm-1)-ma*ma;                double _x=(double)a1/(nn*mm-1);                double val=1.0*(a2-2*_x*a1+(nn*mm-1)*_x*_x)/(nn*mm-1);                if(fancha<0||fancha>val){                    fancha=val;                    posx=x;posy=y;                }                //printf("%lf\n",a2-2*_x*a1+(nn*mm-1)*_x*_x);                //printf("%d %lf %lf\n",a2,2*_x*a1,(nn*mm-1)*_x*_x);                //printf("%d %d ma:%d a1:%d a2:%d val:%lf _x:%lf\n",x,y,ma,a1,a2,val,_x);            }            if(fancha<0)fancha=0.0;            printf("(%d, %d), %.2lf\n",posx,posy,fancha);        }    }    return 0;}


0 0
原创粉丝点击