二分+前缀(预处理神力2)

1. 问题

我们要计算:

复制代码
S=i=1∑N​j=1∑M​∣Ai​−Bj​∣mod998244353

其中 N,M≤3×105,不能暴力 O(NM)。

2. 数学推导

对于每个固定的 Ai​:

复制代码
j=1∑M​∣Ai​−Bj​∣=Bj​≤Ai​∑​(Ai​−Bj​)+Bj​>Ai​∑​(Bj​−Ai​)

设 k= 小于等于 Ai​的 Bj​的数量,S≤​= 这些 Bj​的和,S>​= 大于 Ai​的 Bj​的和,且 S>​=sum(B)−S≤​。

则:

复制代码
贡献=(Ai​⋅k−S≤​)+((S>​)−Ai​⋅(M−k))

整理:

复制代码
=Ai​⋅k−S≤​+S>​−Ai​⋅M+Ai​⋅k
复制代码
=(2k−M)⋅Ai​+(S>​−S≤​)
复制代码
=(2k−M)⋅Ai​+(sum(B)−2S≤​)

3. 算法步骤

  1. 对 B排序

  2. 计算 B的前缀和数组

  3. 对每个 Ai​:

    • 在排序后的 B中二分找到第一个大于 Ai​的位置 p

    • 则 k=p(下标从0开始)

    • S≤​=prefp

    • 代入公式计算贡献

  4. 累加所有贡献,取模输出

4. 时间复杂度

  • 排序:O(MlogM)

  • 二分查找:O(NlogM)

  • 总复杂度:O((N+M)logM),可行

5. 取模处理

模数 MOD=998244353,注意:

  • 所有加减乘都要取模

  • 处理负数:(x % MOD + MOD) % MOD

    #include <bits/stdc++.h>
    using namespace std;
    const int MOD = 998244353;

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

    复制代码
      int N, M;
      cin >> N >> M;
      
      vector<long long> A(N), B(M);
      for (int i = 0; i < N; i++) cin >> A[i];
      for (int i = 0; i < M; i++) cin >> B[i];
      
      // 1. 对B排序
      sort(B.begin(), B.end());
      
      // 2. 计算B的前缀和(模MOD)
      vector<long long> pref(M + 1, 0);
      for (int i = 0; i < M; i++) {
          pref[i + 1] = (pref[i] + B[i]) % MOD;
      }
      
      long long total_B_sum = pref[M] % MOD;  // B的总和
      
      long long ans = 0;
      
      // 3. 对每个A[i]计算贡献
      for (int i = 0; i < N; i++) {
          long long ai = A[i] % MOD;
          
          // 二分查找:第一个大于ai的位置
          int p = upper_bound(B.begin(), B.end(), ai) - B.begin();
          // p 就是小于等于ai的元素个数
          
          long long k = p;
          long long S_le = pref[p] % MOD;  // 小于等于ai的部分和
          
          // 贡献 = (2k - M) * ai + (total_B_sum - 2*S_le)
          long long term1 = ((2 * k - M) % MOD) * ai % MOD;
          long long term2 = (total_B_sum - 2 * S_le) % MOD;
          
          long long contribution = (term1 + term2) % MOD;
          ans = (ans + contribution) % MOD;
      }
      
      // 处理负数
      ans = (ans % MOD + MOD) % MOD;
      cout << ans << "\n";
      
      return 0;

    }

相关推荐
xuhaoyu_cpp_java27 分钟前
项目学习(三)分页查询
java·经验分享·笔记·学习
小宋加油啊2 小时前
机械臂抓取物体 PVN3D算法调研学习
学习·算法·3d
lqqjuly2 小时前
前沿算法深度解析(一)
算法
小欣加油3 小时前
leetcode1926 迷宫中离入口最近的出口
数据结构·c++·算法·leetcode·职场和发展
Cloud_Shy6184 小时前
解读《Effective Python 3rd Edition》:从练气到老魔(第五章 Item 33 - 35)
开发语言·人工智能·笔记·python·学习方法
做cv的小昊4 小时前
计算机图形学:【Games101】学习笔记08——光线追踪(辐射度量学、渲染方程与全局光照、蒙特卡洛积分与路径追踪)
图像处理·笔记·学习·计算机视觉·游戏引擎·图形渲染·概率论
星恒随风4 小时前
C++ 类和对象入门(五):初始化列表、explicit 和 static 成员详解
开发语言·c++·笔记·学习·状态模式
浪客灿心4 小时前
项目篇:模块设计与实现
数据库·c++
牛油果子哥q4 小时前
【C++ STL vector】C++ STL vector 终极精讲:动态数组底层原理、两倍扩容机制、迭代器失效、增删查改、性能剖析与工程避坑指南
开发语言·c++