zoukankan      html  css  js  c++  java
  • 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;
    }

     

  • 相关阅读:
    Java 垃圾回收
    位运算符
    VBA中练习ADO:ActiveX Data Object
    使用VB6制作RTD函数
    VBA中使用JavaScript脚本语言解析JSON数据
    VB洗牌算法产生随机数组
    关于VB里判断逻辑的说明
    在VB中动态执行VBS代码,可操控窗体控件
    VB使用API进行RC4加密解密(MD5密钥)
    VB输出数据到EXCEL
  • 原文地址:https://www.cnblogs.com/zjbztianya/p/3061192.html
Copyright © 2011-2022 走看看