您的位置:首页 > 其它

zoj 3614 二维RMQ

2012-10-23 20:27 441 查看
链接: http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=4738

题意:给你一个 n * m 的矩阵,然后有Q次询问,求一个a * b 的 子矩阵,使其方差最小(去掉子矩阵的最大值以后)

分析:n 和 m 的范围是 0 - 300,q 最大为100,枚举的话是10 ^ 6,这就要求我们在O(1) - O(n^2) 内求出子矩阵的方差,我们可以将方差拆开,预处理下需要的数据,然后可以在 O(1)的时间内求出方差,其中方差拆开如下 方差 = (矩阵平方和 + n × 平均值 × 平均值 - 2 × 平均值 × 矩阵和) / n(n为矩阵内的元素个数) ,求的过程中减去最大值,rmq预处理之后可以在0(1)内求出矩阵最值。

code:

#include<stdio.h>
#include<string.h>
#include<math.h>
#define max(a,b) ((a)>(b)?(a):(b))
#define INF (double) 1e30
const int maxn = 301;
int mat[maxn][maxn],r,c,q,dp[maxn][maxn][9][9];;
double sum[maxn][maxn],sum_2[maxn][maxn],lie[maxn][maxn],lie_2[maxn][maxn];
int query_2d(int x1,int x2,int y1,int y2);
void init();
void solve(int a,int b);
void RMQ_2D();
int main()
{
int cas = 1;
while(scanf("%d%d",&r,&c) != EOF)
{
for(int i = 1; i <= r; i ++)
for(int j = 1; j <= c; j ++)
scanf("%d",&mat[i][j]);
printf("Case %d:\n",cas ++);
init();
RMQ_2D();
scanf("%d",&q);
while(q --)
{
int a,b;
scanf("%d%d",&a,&b);
solve(a - 1,b - 1);
}
}
return 0;
}
void init()
{
int i,j;
for(int i = 1; i <= r; i ++)//init lie
for(int j = 1; j <= c; j ++)
{
lie[i][j] = lie[i - 1][j] + mat[i][j];
lie_2[i][j] = lie_2[i - 1][j] + mat[i][j] * mat[i][j];
}
for(int i = 1; i <= r; i ++)
for(int j = 1; j <= c; j ++)
{
sum[i][j] = sum[i][j - 1] + lie[i][j];
sum_2[i][j] = sum_2[i][j - 1] + lie_2[i][j];
}
}
void solve(int a,int b)
{
int ans_x,ans_y;
double ans = INF;
for(int i = 1;i + a <= r;i ++)
{
for(int j = 1;j + b <= c;j ++)
{
int n = (a + 1) * (b + 1) - 1;
int rq = query_2d(i,i + a,j,j + b);
double tp = sum_2[i + a][j + b] - sum_2[i + a][j - 1] - sum_2[i - 1][j + b] + sum_2[i - 1][j - 1] - rq * rq;//平方和
double tv = sum[i + a][j + b] - sum[i + a][j - 1] - sum[i - 1][j + b] + sum[i - 1][j - 1] - rq;//和
double ae = tv / n;
double here = (tp + n * ae * ae - 2 * ae * tv) / n;
if(here < ans)
{
ans_x = i;
ans_y = j;
ans = here;
}
}
}
printf("(%d, %d), %.2f\n",ans_x,ans_y,ans);
}
void RMQ_2D()
{
for(int i = 1; i <= r; i ++)
for(int j = 1; j <= c; j ++)
dp[i][j][0][0] = mat[i][j];
int t = (int) (log((double)c) / log(2.0));
for(int i = 0; i <= t; i ++)
{
for(int j = 0; j <= t; j ++)
{
if(i == 0 && j == 0) continue;
for(int row = 1; row + (1 << i) - 1 <= r; row ++)
{
for(int col = 1; col + (1 << j) - 1 <= c; col ++)
{
if(i == 0) dp[row][col][i][j] = max(dp[row][col][i][j - 1] , dp[row][col + (1 << (j - 1))][i][j - 1]);
else dp[row][col][i][j] = max(dp[row][col][i - 1][j],dp[row + (1 << (i - 1))][col][i - 1][j]);
}
}
}
}
}
int query_2d(int x1,int x2,int y1,int y2)
{
int kx = log(double(x2 - x1 + 1)) / log(2.0);
int ky = log(double(y2 - y1 + 1)) / log(2.0);
int m1 = dp[x1][y1][kx][ky];
int m2 = dp[x2 - (1 << kx) + 1][y1][kx][ky];
int m3 = dp[x1][y2 - (1 << ky) + 1][kx][ky];
int m4 = dp[x2 - (1 << kx) + 1][y2 - (1 << ky) + 1][kx][ky];
int ans = max(max(m1,m2),max(m3,m4));
return ans;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: