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;
}

 

原文地址:https://www.cnblogs.com/zjbztianya/p/3061192.html