NC14380 位数差

题目

题目描述

给一个数组 \({a}\) ,定义 \(h(a,b)\) 为在十进制下 \(a + b\)\(a\) 的位数差,求 \(\displaystyle\sum_{1\leq i < j \leq n} h(a_i,a_j)\)\(0\) 的位数为 \(1\)

输入描述

第一行读入一个正整数 \(n (1 <= n <= 10^5)\)。第二行读入 \(n\) 个非负整数,第 \(i\) 个表示 \(a[i] (0 <= a[i] <= 10^8)\)

输出描述

一行表示答案。

示例1

输入

10
0 1 2 3 4 5 6 7 8 9

输出

20

题解

知识点:二分,数学。

我们用 \(bit(a)\) 表示 \(a\) 的十进制位数,则有:

\[\begin{align*} \displaystyle\sum_{1\leq i < j \leq n} h(a_i,a_j) &= \displaystyle\sum_{1\leq i < j \leq n} bit(a_i+a_j) - bit(a_i)\\ &=\displaystyle\sum_{1\leq i < j \leq n} bit(a_i+a_j) - \displaystyle\sum_{1\leq i < j \leq n}bit(a_i)\\ &=\displaystyle\sum_{1\leq i < j \leq n} bit(a_i+a_j) - \displaystyle\sum_{1\leq i \leq n}(n-i)bit(a_i)\\ &=\displaystyle\sum_{1\leq i < j \leq n} bit(a_i+a_j) - \displaystyle\sum_{1\leq i < j \leq n}(n-i)bit(a_i)\\ \end{align*} \]

其中,\(- \displaystyle\sum_{1\leq i < j \leq n}(n-i)bit(a_i)\) 可以在输入时候处理完。

\(\displaystyle\sum_{1\leq i < j \leq n} bit(a_i+a_j)\)\(i\)\(j\) 顺序可以互换,因此该式与序列的排列顺序无关。所以从小到大排序,对每一个数查找某一结果的区间,由于选择比 \(a_i\) 小的数与 \(a_i\) 配对答案只可能是 \(0\)\(1\) 而选择大的数会出现 \(0\)\(9\) ,而选择一种即可结果是相同的,我们选择前者查找答案 \(01\) 分界点,非常方便。显然只要查找大于等于 \(10^{bit(a_i)} - a_i\) 的第一个数 \(a_{pos}\),即第一个 \(bit(a_i+a_j)\) 结果为 \(bit(a_i)+1\) 的数即可。随后因为这个区间的所有数的位数至少是 \(bit(a_i)\) ,因此加上 \((i-1)bit(a_i)\) ,再加上位数多一的个数 \((i-pos)\) ,于是对于这个数与小于他的数的配对总和就是 \((i-1)bit(a_i)+(i-pos)\) ,对每个数如此操作即可。

时间复杂度 \(O(n \log n)\)

空间复杂度 \(O(n)\)

代码

#include <bits/stdc++.h>
#define ll long long

using namespace std;

int a[100007];
int p[10] = { 1,10,100,1000,10000,100000,1000000,10000000,100000000 };

int bit(int n) {
    if (!n) return 1;
    int ans = 0;
    while (n) n /= 10, ans++;
    return ans;
}

int main() {
    std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int n;
    cin >> n;
    ll ans = 0;
    for (int i = 1;i <= n;i++) cin >> a[i], ans -= (n - i) * bit(a[i]);
    sort(a + 1, a + n + 1);
    for (int i = 1;i <= n;i++) {
        int pos = lower_bound(a + 1, a + i, p[bit(a[i])] - a[i]) - a;
        ans += (i - 1) * bit(a[i]) + (i - pos);
    }
    cout << ans << '\n';
    return 0;
}
posted @ 2022-06-28 14:37  空白菌  阅读(46)  评论(0)    收藏  举报