首页 > 其他分享 >洛谷 P6692 题解

洛谷 P6692 题解

时间:2024-04-10 23:57:50浏览次数:20  
标签:洛谷 circ P6692 题解 sum int 1ll aligned MOD

洛谷 P6692 出生点

题意简述

\(n\) 行 \(m\) 列构成 \(nm\) 个格点,在其中指定 \(k\) 个障碍点。每行、每列之间的距离为 \(1\),每次任意选取两个非障碍点,计算这两个点的曼哈顿距离,求所有选法的距离之和。

分析

由容斥原理,答案为「任意两点之间的距离之和」\(-\)「每个障碍点到其他所有点的距离之和」\(+\)「任意两障碍点之间的距离之和」。下面分别考虑这三部分怎么求。

前置知识

\[\sum_{i=1}^n i = \frac{n(n+1)}{2} \\ \sum_{i=1}^n i^2 = \frac{n(n+1)(2n+1)}{6} \]

两式可以由数学归纳法证明。

任意两点之间的距离之和

显然行和列是等价的,下面考虑行之间的距离,即纵坐标对答案的贡献。

\[i \; \overbrace{\circ \circ \cdots \circ \circ}^m \\ \cdots \\ j \circ \circ \cdots \circ \circ \]

如图,我们任意选取两行,不妨设为第 \(i\) 行和第 \(j\) 行(\(1 \le i < j \le n\))。在第 \(i\) 行和第 \(j\) 行各任选 \(1\) 个点,由乘法原理知共有 \(m^2\) 种选法。显然这两点纵坐标的差为 \(j-i\)。所以,第 \(i\) 行和第 \(j\) 行的纵坐标对答案的贡献为 \(m^2 \cdot (j-i)\)。

枚举 \(i, j\),我们得到纵坐标对答案的贡献为:

\[m^2 \sum_{i=1}^{n-1} \sum_{j=i+1}^{n} (j-i) \]

考虑化简:

\[\begin{aligned} m^2 \sum_{i=1}^{n-1} \sum_{j=i+1}^{n} (j-i) &= m^2 \sum_{i=1}^{n-1} \sum_{i=1}^{n-i} j \\ &= m^2 \begin{pmatrix} \begin{aligned} &1+2+ \cdots +(n-2)+(n-1) \\ +&1+2+ \cdots +(n-2) \\ +& \cdots \\ +&1+2 \\ +&1 \end{aligned} \end{pmatrix}\\ &= m^2 \sum_{i=1}^{n-1} [i \cdot (n-i)] \\ &= m^2 \sum_{i=1}^{n-1} [in-i^2] \\ &= m^2 n \sum_{i=1}^{n-1} i-m^2 \sum_{i=1}^{n-1} i^2 \end{aligned} \]

这样化简的好处是可以直接套用两个公式,时间复杂度 \(O(1)\) 。

横坐标同理。综上,「任意两点之间的距离之和」为

\[m^2 n \sum_{i=1}^{n-1} i-m^2 \sum_{i=1}^{n-1} i^2+n^2 m \sum_{i=1}^{m-1} i-n^2 \sum_{i=1}^{m-1} i^2 \]

每个障碍点到其他所有点的距离之和

直接枚举每个障碍点,显然 \(\sum_{i=1}^k \sum_{x=1}^n \sum_{y=1}^m (|x_i-x|+|y_i-y|)\) 即为所求。

类似地,考虑化简:

\[\begin{aligned} \sum_{i=1}^k \sum_{x=1}^n \sum_{y=1}^m (|x_i-x|+|y_i-y|) &= \sum_{i=1}^k (\sum_{x=1}^n \sum_{y=1}^m |x_i-x|+\sum_{x=1}^n \sum_{y=1}^m |y_i-y|) \\ &= \sum_{i=1}^k (m \sum_{x=1}^n |x_i-x|+n \sum_{y=1}^m |y_i-y|) \\ &= \sum_{i=1}^k (m \sum_{x=1}^{x_i-1} (x_i-x)+m \sum_{x = x_i+1}^{n} (x-x_i)+n \sum_{y=1}^{y_i-1} (y_i-y)+n \sum_{y = y_i+1}^{m} (y-y_i)) \\ &= \sum_{i=1}^k (m \sum_{x=1}^{x_i-1} x+m \sum_{x=1}^{n-x_i}+n \sum_{y=1}^{y_i-1} y+n \sum_{y=1} ^ {m-y_i}) \end{aligned} \]

时间复杂度 \(O(k)\)。

任意两障碍点之间的距离之和

将 \(x\) 从小到大排序。设 \(f_i = \sum_{i=1}^{i-1} (x_i-x_j)\)。特别地,\(f_1 = 0\)。则显然 \(\sum_{i=1}^{k} f_i\) 即为所求。

有递推式 \(f_i = f_{i-1}+(i-1) \cdot (x_i-x_{i-1})\)。

证明:

\[\begin{aligned} f_i &= \sum_{i=1}^{i-1} (x_i-x_j) \\ &= \sum_{i=1}^{i-2} (x_i-x_j)+x_i-x_{i-1} \\ &= \sum_{i=1}^{i-2} [(x_i-x_{i-1})+(x_{i-1}-x_j)]+x_i-x_{i-1} \\ &= \sum_{i=1}^{i-2} (x_i-x_{i-1})+f_{i-1}+x_i-x_{i-1} \\ &= f_{i-1}+(i-1) \cdot (x_i-x_{i-1}) \end{aligned} \]

因此递推 \(f\) 的同时累加答案即可,\(y\) 同理。

时间复杂度 \(O(k \log k)\)。

代码

#include <iostream>
#include <algorithm>

const int MOD = 1e9 + 7;

int x[500005], y[500005];

int sum1(int n) // 公式 1
{
    return 1ll * n * (n + 1) / 2 % MOD;
}

int sum2(int n) // 公式 2
{
    // 注意被 6 整除的问题
    // n * (n + 1) 一定被 2 整除, 因此只需讨论 n, (n + 1), (2 * n + 1) 中哪个因式被 3 整除
    if (n % 3 == 1) // 此时 (2 * n + 1) 被 3 整除
        return 1ll * n * (n + 1) / 2 % MOD * (2 * n + 1) / 3 % MOD;
    return 1ll * n * (n + 1) / 6 % MOD * (2 * n + 1) % MOD; // 否则 n 和 (n + 1) 一定有一个被 3 整除
}

int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);

    int n, m, k;
    long long f, ans = 0;

    std::cin >> n >> m >> k;
    for (int i = 1; i <= k; i++)
        std::cin >> x[i] >> y[i];

    // 任意两点之间的距离之和
    ans += 1ll * m * m % MOD * n % MOD * sum1(n - 1) % MOD;
    ans -= 1ll * m * m % MOD * sum2(n - 1) % MOD;
    ans += 1ll * n * n % MOD * m % MOD * sum1(m - 1) % MOD;
    ans -= 1ll * n * n % MOD * sum2(m - 1) % MOD;
    ans = (ans % MOD + MOD) % MOD; // 取模时注意负数

    // 每个障碍点到其他所有点的距离之和
    for (int i = 1; i <= k; i++)
    {
        ans -= 1ll * m * sum1(x[i] - 1) % MOD;
        ans -= 1ll * m * sum1(n - x[i]) % MOD;
        ans -= 1ll * n * sum1(y[i] - 1) % MOD;
        ans -= 1ll * n * sum1(m - y[i]) % MOD;
        ans = (ans % MOD + MOD) % MOD; // 取模时注意负数
    }

    // 任意两障碍点之间的距离之和
    f = 0;
    std::sort(x + 1, x + k + 1);
    for (int i = 2; i <= k; i++)
    {
        f += 1ll * (i - 1) * (x[i] - x[i - 1]) % MOD;
        f %= MOD;
        ans += f;
        ans %= MOD;
    }
    f = 0;
    std::sort(y + 1, y + k + 1);
    for (int i = 2; i <= k; i++)
    {
        f += 1ll * (i - 1) * (y[i] - y[i - 1]) % MOD;
        f %= MOD;
        ans += f;
        ans %= MOD;
    }

    std::cout << ans << "\n";

    return 0;
}

标签:洛谷,circ,P6692,题解,sum,int,1ll,aligned,MOD
From: https://www.cnblogs.com/lzy20091001/p/18127808/Luogu-P6692-solution

相关文章

  • #莫队二次离线,根号分治#洛谷 5398 [Ynoi2018] GOSICK
    题目\(m\)组询问求\(\sum_{l\leqi,j\leqr}[a_i\bmoda_j==0],n,m,a_i\leq5\times10^5\)分析设\(f(l,r,x)\)表示\(i或j\in[1,x],i或j\in[l,r]\)时的答案,\(g_x\)表示\([1,x]\)的答案,根号的做法可以通过三秒由于涉及区间内的求值,需要在莫队的基础上二次离线,那......
  • CF358B Dima and Text Messages 题解
    大家好,我不喜欢string,所以我选择用char来写。题目传送门,但不是洛谷。吐槽一下,这个翻译翻译的并不好,翻译中并没有说明“爱心”是指<3,还是得去自己翻。正文将读入的单词连在一起,并穿插爱心,注意这里首尾都是爱心,需要手动补充。最后将得到的序列与输入的字符串进行比对即可。......
  • 2024年3月电子学会青少年软件编程 中小学生Python编程等级考试一级真题解析(判断题)
    2024年3月Python编程等级考试一级真题解析判断题(共10题,每题2分,共20分)26、turtle画布的坐标系原点是在画布的左上角答案:错考点分析:考查turtle相关知识,turtle画布坐标系是在画布的中点,答案错误27、Python变量名区分大小写,book和BOOK不是同一个变量答案:对考点分析:考查......
  • CF1250A Berstagram 题解
    题面。题意描述的很清楚,这里就不多赘述。思路看题,对于每个\(a_i\),若\(b_j=a_i\),则将\(b_j\)与\(b_{j-1}\)的值调换(若\(j=1\),则序列不变)。一开始想的是最直接的暴力,复杂度为\(O(nm)\),虽然开了三秒的时限,但\(4\times10^{10}\)的数据明显不是三秒钟就能解决的,含恨倒在第......
  • P8791 [蓝桥杯 2022 国 AC] 内存空间 题解
    题面一道比较简单模拟题,但是要分类讨论一.读完题你应该知道的1.输入一共有T+1行,输入含有空格。(处理1)2.对于每一行变量定义的语句,只会出现一种变量类型,type只可能是int或long,只有一个分号。(处理1,处理2)3.统计内存过程中用B做单位,保证一定有输出,但在输出时要换......
  • CF1681C Double Sort 题解
    一道普及-我写了两个半小时题面。需要注意的是,每次交换需要将a和b两个数组同时交换,因此便可以想到唯一可行情况:a,b序列数字间的大小关系必须一致。举个例子2462131317970612在上面的例子中,两个序列中任意\(i\)和\(j\)满足\(a_i\lea_j\)时\(b_i......
  • CF958F1 Lightsabers (easy) 题解
    题面。不好意思,当我看到\(1\len\le100\),\(1\lem\len\)的那一刻,我承认我心动了。题目没翻译,用翻译软件翻译了才看懂。思路依据题意直接模拟即可。这里我用了三层循环来模拟。第一层为\(len\),表示长度;第二层为\(from\),表示出发点,此时需要遍历的区间的终点\(to=from......
  • CF1040B Shashlik Cooking 题解
    题面。看到这道题的第一眼,就想到用分块思想来解决。思路我们知道,当对任意一个\(i\)进行翻转时,区间\([i-k,i+k]\)内的所有元素都会翻转,每次翻转的总个数为\(2\timesk+1\)。因此,我们可以将所有烤串分成长度为\(len=2\timesk+1\)的\(block=n\divlen\)块,用数组\(L......
  • CF158C Cd and pwd commands 题解
    题面。大模拟,但是有坑点。思路依照题意模拟。用一个字符串\(out\)记录在进行了\(i\)次操作后如果要输出输出的东西,字符串\(in\)和\(s\)来分别记录输入的操作及操作类型。由于输出的第一个字符一定是/,所以可以直接将\(out\)的初始化定为out="/"。这样子可以省去......
  • CF875B Sorting the Coins 题解
    题面。算是比较简单的题目了,自己多手出几个样例就可以发现规律了。强烈建议多读几遍题目!!!!思路设0表示硬币朝上,1表示硬币朝下,则第\(0\)次与第\(n\)操作一定输出\(1\)。因为没有可以操作的对象,前者是由于全部硬币朝上,后者是由于全部硬币朝下,即使没有操作也要遍历一遍。注......