二分+前缀(预处理神力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≤​=pref[p]

    • 代入公式计算贡献

  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;

    }

相关推荐
Westward-sun.12 分钟前
OpenCV + dlib 人脸关键点检测学习笔记(68点)
人工智能·笔记·opencv·学习·计算机视觉
_日拱一卒12 分钟前
LeetCode:240搜索二维矩阵Ⅱ
数据结构·线性代数·leetcode·矩阵
WolfGang00732112 分钟前
代码随想录算法训练营 Day33 | 动态规划 part06
算法·leetcode·动态规划
aini_lovee13 分钟前
半定规划(SDP)求解的 MATLAB 实现
算法
米粒124 分钟前
力扣算法刷题 Day 41(买卖股票)
算法·leetcode·职场和发展
幻风_huanfeng26 分钟前
人工智能之数学基础:内点法和外点法的区别和缺点
人工智能·算法·机器学习·内点法·外点法
天若有情67327 分钟前
颠覆C++传统玩法!Property属性与伪类,开辟静态语言新维度
java·c++·servlet
MIngYaaa52034 分钟前
The 6th Liaoning Provincial Collegiate Programming Contest - External 复盘
算法
chushiyunen35 分钟前
阿里云部署dify笔记
笔记·阿里云·云计算
CylMK36 分钟前
题解:P11625 [迷宫寻路 Round 3] 迷宫寻路大赛
c++·数学·算法