首先把矩阵和和矩阵平方和算出来,然后枚举每一个位置,中间计算的时候要减去最大值,这里就用到了二维RMQ O(1)的时间
写的时候用int溢出,找了好久.
方差 = (矩阵平方和 + n × 平均值 × 平均值 - 2 × 平均值 × 矩阵和) / n(n为矩阵内的元素个数)
#include <iostream>
#include <memory.h>
#include <cstdio>
#include <cmath>
using namespace std;
const int maxn=301;
#define mmax(a,b) ((a)>(b)?(a):(b))
int dp[maxn][maxn][9][9],grid[maxn][maxn],N,M,Q;
double t2[maxn][maxn],qSum[maxn][maxn],t1[maxn][maxn],sum[maxn][maxn];
void init(){
for (int i=1;i<=N;++i){
for (int j=1;j<=M;++j){
t1[i][j]=t1[i-1][j]+grid[i][j];
t2[i][j]=t2[i-1][j]+grid[i][j]*grid[i][j];
}
}
for (int i=1;i<=N;++i){
for (int j=1;j<=M;++j){
sum[i][j]=sum[i][j-1]+t1[i][j];
qSum[i][j]=qSum[i][j-1]+t2[i][j];
}
}
for (int i=1;i<=N;++i){
for (int j=1;j<=M;++j){
dp[i][j][0][0]=grid[i][j];
}
}
int km=int(log((double)M)/log(2.0));
for (int i=0;i<=km;++i){
for (int j=0;j<=km;++j){
if(i==0&&j==0)continue;
for (int ii=1;ii+(1<<i)-1<=N;++ii){
for (int jj=1;jj+(1<<j)-1<=M;++jj){
if(i==0){
dp[ii][jj][i][j]=mmax(dp[ii][jj][i][j-1],dp[ii][jj+(1<<(j-1))][i][j-1]);
}else{
dp[ii][jj][i][j]=mmax(dp[ii][jj][i-1][j],dp[ii+(1<<(i-1))][jj][i-1][j]);
}
}
}
}
}
}
int query(int x1,int x2,int y1,int y2){
int k_x=log((double)x2-x1+1)/log(2.0),k_y=log((double)y2-y1+1)/log(2.0);
int v1=mmax(dp[x1][y1][k_x][k_y],dp[x2-(1<<k_x)+1][y1][k_x][k_y]);
int v2=mmax(dp[x1][y2-(1<<k_y)+1][k_x][k_y],dp[x2-(1<<k_x)+1][y2-(1<<k_y)+1][k_x][k_y]);
return mmax(v1,v2);
}
int main(){
int cas=1;
while (scanf("%d%d",&N,&M)!=EOF){
memset(sum,0,sizeof(sum));
memset(qSum,0,sizeof(qSum));
memset(t1,0,sizeof(t1));
memset(t2,0,sizeof(t2));
for (int i=1;i<=N;++i){
for (int j=1;j<=M;++j){
scanf("%d",&grid[i][j]);
}
}
init();
scanf("%d",&Q);
printf("Case %d:\n",cas++);
while (Q--){
int a,b,ansi,ansj;
double ansv=1e30;
scanf("%d%d",&a,&b);
a--,b--;
for (int i=1;i+a<=N;++i){
for (int j=1;j+b<=M;++j){
int res=query(i,i+a,j,j+b),n=(a+1)*(b+1)-1;
double subSum=sum[i+a][j+b]-sum[i+a][j-1]-(sum[i-1][j+b]-sum[i-1][j-1])-res;
double subQSum=qSum[i+a][j+b]-qSum[i+a][j-1]-(qSum[i-1][j+b]-qSum[i-1][j-1])-res*res;
double avg=subSum/n;
double var=(subQSum+n*avg*avg-2*avg*subSum)/n;
if(var<ansv){
ansi=i;
ansj=j;
ansv=var;
}
}
}
printf("(%d, %d), %.2f\n",ansi,ansj,ansv);
}
}
return 0;
}