[数学推导] aw3782. 点(推公式+数学推导+数学证明+CF76E)

1. 题目来源

链接:3782. 点

2. 题目解析

两点之间距离,为了不重复计算,给每个点编号,并定义其有序性。然后发现,xy 完全可以独立计算。然后推公式即可,公式中有重要的优化需要谨记。
在这里插入图片描述


但其实,从分析的角度上来考虑,单独考虑一个点与其它所有点的所得贡献。

  • 两两组队,每个 x^2 出现 n-1 次是显然的。简单画个图,列举情况就懂了。故当前点 x^2 贡献了 (n-1)*x[i]*x[i] 次,将平方的总贡献累加即可。
  • 同理其中出现的 2x1*x2 的情况,固定一个 x1,那么有 n-1xi 将于 x1 配对,提取公因式的话,就是除过 x1 的所有数均要与 x1 相乘,这个维护一个总数,减去当前数 x1 即可得到。
  • 同时,2x1*x2 的部分,其实是被计算了两次,即在考虑 x1 点时,考虑了其它各点,在考虑其它各点时,又考虑了 x1 这个点,所以是重复计算了一次,除 2 就行了。
  • 也可以用笔记中的,将 2x1*x2 这部分的有序性消除,变成 xi*xj 无序,即可。

或者说,我们在考虑 (x1,y1) 点时,仅考虑这个点所带来的贡献,即它在所有的配对中,一共贡献了 n-1x1*x1n-1y1*y1,在 2x1*x2 这个部分,这其实是由两个点所带来的,我们仅取和自己相关的一部分,即仅计算一个 x1*x2

好好理解就行,理解不了就直接上数学公式就行了。


时间复杂度: O ( n ) O(n) O(n)

空间复杂度: O ( n ) O(n) O(n)


完美的数学公式推导

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;

const int N = 1e5+5;

int n;
int x[N], y[N];

LL cal(int x[]) {
    LL s1 = 0, s2 = 0;
    for (int i = 0; i < n; i ++ ) s1 += x[i] * x[i], s2 += x[i];
    
    return (n - 1) * s1 - (s2 * s2 - s1);
}

int main() {
    cin >> n;
    for (int i = 0; i < n; i ++ ) cin >> x[i] >> y[i];
    cout << cal(x) + cal(y) << endl;
    
    return 0;
}

形象化的计算,考虑每个点的贡献:

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;

const int N = 1e5+5;

int n;
int x[N], y[N];

int main() {
    cin >> n;
    LL s1 = 0, s2 = 0;
    LL res1 = 0, res2 = 0;
    for (int i = 0; i < n; i ++ ) cin >> x[i] >> y[i], s1 += x[i], s2 += y[i];
    for (int i = 0; i < n; i ++ ) {
        res1 += 1ll * (n - 1) * x[i] * x[i] - x[i] * (s1 - x[i]);   // 在此可以不用乘2,2x1*x2 本身就重复计算了一次
        res2 += 1ll * (n - 1) * y[i] * y[i] - y[i] * (s2 - y[i]);
    }
    cout << res1 + res2 << endl;
    
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ypuyu

如果帮助到你,可以请作者喝水~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值