二分+前缀(预处理神力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;

    }

相关推荐
一米阳光86613 小时前
软考高级【信息系统项目管理师】高项重要考点(3)高级项目管理-下 助你顺利上岸!
笔记·职场发展·软考·信息系统项目管理师·高级职称
hqyjzsb3 小时前
零 AI 项目经验,学 Python 转型 AI 的正确顺序是什么?
开发语言·人工智能·python·算法·职场和发展·数据挖掘·数据分析
辰烨chenye3 小时前
LeetCode Hot 100 题解 · 二分篇
java·算法·leetcode
微功夫信息技术3 小时前
分层多智能体强化学习驱动的非急救转运公平 - 效率统一调度系统研究与实践
人工智能·学习·算法·动态规划
dianziyao_4 小时前
第 4.1 篇:让 Codex 理解你的双链——AI 辅助发现笔记间的关联
人工智能·笔记
sanjiaomao3334 小时前
从论文公式到Python实现:用单元测试校验滑动平均算法
python·算法·单元测试
Keven_114 小时前
算法札记:ACM适用的很骚的C++语法(持续更新)
开发语言·c++
乐迪信息4 小时前
如何通过AI防爆摄像机精准判断船舶超速?
大数据·人工智能·算法·安全·目标跟踪
mengzhi啊5 小时前
QPluginLoader 动态 DLL 插件版,支持插件之间通信,广播。请求和应答
c++·qt
雨落在了我的手上5 小时前
Java数据结构(十一):优先级队列(堆)
数据结构