现哥的兰博基尼(rich.pas/c/cpp)
Time Limit:1s Memory Limit:256MB
【题目描述】
现哥准备现在从没钱开始攒钱买辆兰博基尼!1秒……2秒……3秒……好吧,攒够了!
现哥附近的广场正好有家兰博基尼的车展会。这个展会由多个4×4的平台组成。每个平台的中心都有一辆兰博基尼。但是很不科学的是这里有N行M列平台,也就意味着有N×M辆兰博基尼,而兰博基尼是全球限量发售的,一次出现如此多的兰博基尼说明其中大部分都是冒牌货!而冒牌货中有高端的,也有低端的,而冒牌货的高端低端可以表示成冒牌指数k,k越大意味着这个冒牌货越高端。而k达到一定大小时就是正品了。现哥一眼就看出了所有N*M辆兰博基尼的k值,但是他想找一个地方,站在那里,仔细研究每辆兰博基尼。如果将整个展台看作平面直角坐标系,4×4平台的边界平行于坐标轴。以左下角平台的左下角端点作为原点,那么展台的图如下图所示:
上图每个正方形的中央都有辆兰博基尼。
假定现哥所在坐标(x1,y1),现哥所观察的兰博基尼的坐标为(x2,y2),冒牌指数为k,那么现哥观察这辆兰博基尼所花时间为k*((x1-x2)2+(y1-y2)2),而现哥希望找到一个位置(x,y)使得他观察所有兰博基尼的所需要的总时间最少。特别的,由于现哥想站在4×4平台的端点上,所以他要求他所在的横纵坐标值必须都能被4整除!
【输入格式】
第一行两个数字N,M,表示车展会的规模。
接下来N行,每行M个数字,即第N行M列平台中的兰博基尼的k值。
【输出格式】
输出一行,即现哥观察所有兰博基尼的最小耗时。
【样例输入输出】
rich.in rich.out
2 3
3 4 5
3 9 1 392
【样例解释】
当现哥站在坐标(4,4)上时,观察第一行兰博基尼的耗时分别为:24、32、200。
观察第二行兰博基尼的耗时分别为:24、72、40
总时间为392
【数据范围】
30%的数据:1≤N,M≤50。
100%的数据:1≤N,M≤1000,0≤k≤10^5。
【解题报告】
考试的时候只想到暴力,复杂度为O(n^4) 预期得分30分
我们其实可以化简式子
({sumlimits_{i=1}^{n}sumlimits_{j=1}^{m}Kij*((x-xi)^2+(y-yj)^2) })
=({sumlimits_{i=1}^{n}sumlimits_{j=1}^{m}Kij*(x-xi)^2 }) + ({sumlimits_{i=1}^{n}sumlimits_{j=1}^{m}Kij*(y-yj)^2 })
=({sumlimits_{i=1}^{n}(x-xi)^2sumlimits_{j=1}^{n}Kij }) + ({sumlimits_{j=1}^{m}(y-yj)^2sumlimits_{i=1}^{n}Kij })
对于这两个式子,我们可以预处理把({sumlimits_{i=1}^{n}Kij})和({sumlimits_{j=1}^{m}Kij})求出来,这样,我们只要单独枚举x与y就可以。
预处理O(mn)
枚举O(m2+n2)
注意要开long long!
#include <iostream>
#include <cmath>
#include <queue>
#include <algorithm>
#include <cstring>
#include <climits>
#define MAXN 1000+10
#define MAX LONG_LONG_MAX
using namespace std;
int n,m;
long long g[MAXN][MAXN],gi[MAXN],gj[MAXN];
long long ans=MAX,minx=MAX,miny=MAX;
int main()
{
freopen("rich.in","r",stdin);
freopen("rich.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&g[i][j]);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
gi[i]+=g[i][j];
for(int j=1;j<=m;j++)
for(int i=1;i<=n;i++)
gj[j]+=g[i][j];
for(int x=0;x<=4*n;x+=4)
{
long long temp=0;
for(int i=2;i<=4*n;i+=4)
temp+=1LL*(x-i)*(x-i)*gi[int((i+2)/4.0)];
if(minx>temp) minx=temp;
}
for(int y=0;y<=4*n;y+=4)
{
long long temp=0;
for(int j=2;j<=4*m;j+=4)
temp+=1LL*(y-j)*(y-j)*gj[int((j+2)/4.0)];
if(miny>temp) miny=temp;
}
ans=minx+miny;
printf("%lld
",ans);
return 0;
}