ZOJ3614 - Choir

题目大意

给定一个大小为N*M的矩阵,接下来会给出一些查询,对于每个查询(a,b)要求你返回所有大小为a*b的子矩阵中方差(值最大的除外)最小的子矩阵的左下角坐标和方差

题解

方差公式为:08f61c9020f8d0eb6dbe7d85155a552d,因此我们可以用两个数组来预处理一下,数组suma[i][j]表示左下角为(1,1),右上角为(i,j)的矩阵的和,sumb[i][j]表示左下角为(1,1),右上角为(i,j)的矩阵的平方和,剩下的问题就是在矩阵中找出最大值,这刚好是RMQ问题。。。

代码:

#include<iostream>

#include<cstdio>

#include<cstring>

#include<cmath>

#include<algorithm>

#define MAXN 305

#define INF 10000000000.0

using namespace std;

double d[MAXN][MAXN][9][9];

int a[MAXN][MAXN];

long long suma[MAXN][MAXN],sumb[MAXN][MAXN];

int n,m;

void init_RMQ()

{

    int i,j,ii,jj;

    for(i=1; i<=n; i++)

        for(j=1; j<=m; j++)

            d[i][j][0][0]=a[i][j];

    for(j=0; (1<<j)<=n; j++)

        for(jj=0; (1<<jj)<=m; jj++)

        {

            if(j==0&&jj==0) continue;

            for(i=1; i+(1<<j)-1<=n; i++)

                for(ii=1; ii+(1<<jj)-1<=m; ii++)

                    if(j==0)

                        d[i][ii][j][jj]=max(d[i][ii][j][jj-1],d[i][ii+(1<<(jj-1))][j][jj-1]);

                    else

                        d[i][ii][j][jj]=max(d[i][ii][j-1][jj],d[i+(1<<(j-1))][ii][j-1][jj]);

        }

}

int RMQ(int L1,int R1,int L2,int R2)

{

    int kx=0,ky=0,m1,m2;

    while((1<<(kx+1))<=L2-L1+1) kx++;

    while((1<<(ky+1))<=R2-R1+1) ky++;

    m1=max(d[L1][R1][kx][ky],d[L1][R2-(1<<ky)+1][kx][ky]);

    m2=max(d[L2-(1<<kx)+1][R1][kx][ky],d[L2-(1<<kx)+1][R2-(1<<ky)+1][kx][ky]);

    return max(m1,m2);

}

void init()

{

    int i,j,x,y,q,p=0;

    while(scanf("%d%d",&n,&m)!=EOF)

    {

        printf("Case %d:\n",++p);

        memset(suma,0,sizeof(suma));

        memset(sumb,0,sizeof(sumb));

        for(i=1; i<=n; i++)

            for(j=1; j<=m; j++)

                scanf("%d",&a[i][j]);

        for(i=1; i<=n; i++)

            for(j=1; j<=m; j++)

            {

                suma[i][j]=suma[i][j-1]+suma[i-1][j]+a[i][j]-suma[i-1][j-1];

                sumb[i][j]=sumb[i][j-1]+sumb[i-1][j]+a[i][j]*a[i][j]-sumb[i-1][j-1];

            }

        init_RMQ();

        scanf("%d",&q);

        while(q--)

        {

            long long ansa,ansb;

            long long  t;

            double sa,sb,mins,ans;

            int tx,ty;

            scanf("%d%d",&x,&y);

            mins=INF;

            for(i=1; i<=n-x+1; i++)

                for(j=1; j<=m-y+1; j++)

                {

                    ansa=suma[i+x-1][j+y-1]-suma[i-1][j+y-1]-suma[i+x-1][j-1]+suma[i-1][j-1];

                    ansb=sumb[i+x-1][j+y-1]-sumb[i-1][j+y-1]-sumb[i+x-1][j-1]+sumb[i-1][j-1];

                    t=RMQ(i,j,i+x-1,j+y-1);

                    sa=(ansa-t)*1.0/(x*y-1);

                    sa=sa*sa;

                    sb=(ansb-t*t)*1.0/(x*y-1);

                    ans=sb-sa;

                    if(ans<mins)

                    {

                        tx=i;

                        ty=j;

                        mins=ans;

                    }

                }

            printf("(%d, %d), %.2lf\n",tx,ty,mins);

        }

    }

}

int main(void)

{

    init();

    return 0;

}

 

 

你可能感兴趣的:(ZOJ)