现哥的兰博基尼

题目描述
在给定的图中有N*M个k值,位置为(x,y),现求出一个位置(x1,x2),使得最小;

ni=1nj=1Kij((xxi)2+(yyj)2)

30分打法
暴力枚举,可以不用枚举边界(这样一定不是最优),只需要枚举图的一半;
AC做法
对于所求的式子可以将x,y拆分出来,先预处理出每一行与每一列的kij的和然后分别枚举x,y,求出最小的sum{x},最小的sum{y},答案即为sum{x}+sum{y};

i=1nj=1mKij((xxi)2+(yyj)2)=i=1n(xxi)2j=1mKij+j=1m(yyi)2i=1mKij

代码
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;

typedef long long LL;
int car[1000+10][1000+10];
LL carx[1000+10],cary[1000+10];
int n,m;
LL cnt1=999999999999999999,cnt2=99999999999999999;

LL js1(int i,int x)
{
    return LL(carx[i]*(pow(x-4*i+2,2)));//枚举x的位置
}

LL js2(int j,int y)
{
    return LL(cary[j]*(pow(y-4*j+2,2)));//枚举y的位置
}

void tot1(int x)
{
    LL ans=0;
    for(int i=n;i>=0;i--)
    {
        ans+=js1(i,x);
        if(ans>=cnt1)   return;//一个小剪枝
    }
    cnt1=ans;
}

void tot2(int y)
{
    LL ans=0;
    for(int j=m;j>=0;j--)
    {
        ans+=js2(j,y);
        if(ans>=cnt2)   return;
    }
    cnt2=ans;
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            {
                scanf("%d",&car[i][j]);
                carx[i]+=car[i][j];
                cary[j]+=car[i][j];
            }
    for(int i=4;i<=n*4;i+=4)
    {
        tot1(i);//枚举
    }
    for(int j=4;j<=m*4;j+=4)
    {
        tot2(j);//枚举
    }
    printf("%lld",cnt1+cnt2);
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值