题目大意
给定一个大小为N*M的矩阵,接下来会给出一些查询,对于每个查询(a,b)要求你返回所有大小为a*b的子矩阵中方差(值最大的除外)最小的子矩阵的左下角坐标和方差
题解
方差公式为:,因此我们可以用两个数组来预处理一下,数组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; }