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

    }

相关推荐
垆边人似月.8 分钟前
华为机考题:明明的随机数
数据结构·算法·华为
xailorliu35 分钟前
矩阵定性-正定负定不定半正定半负定
c++·opencv·线性代数·计算机视觉·矩阵
Doubbbbbbble云37 分钟前
多维空间索引结构R树与KD树性能对比研究4
算法
海上小飞龙39 分钟前
【KMP算法-中篇】next 数组的递推:往前填一位,靠的是往回退几步
算法
lusklusklusk40 分钟前
Python 四大数据结构详解:元组、列表、集合、字典的特点与增删改查
数据结构·windows·python
keyipatience43 分钟前
B树详解:从零构建平衡多路搜索树
数据结构·b树·算法·图搜索
个 人 练 习 生44 分钟前
C++-----string基本使用详解
开发语言·c++·学习
朝朝辞暮i1 小时前
C++ 第 5 课:else if + 多条件判断 + && / || / !
开发语言·c++
画绛集美术1 小时前
用开源AI语音合成做课程口播音频:一间美术教室的技术笔记
人工智能·笔记·音视频
千谦阙听1 小时前
【C++篇】:string类——常用接口、底层原理与深浅拷贝
开发语言·c++·学习·visual studio