NC14380 位数差

题目

题目描述

给一个数组 a ,定义 h(a,b) 为在十进制下 a+ba 的位数差,求 1i<jnh(ai,aj)0 的位数为 1

输入描述

第一行读入一个正整数 n(1<=n<=105)。第二行读入 n 个非负整数,第 i 个表示 a[i](0<=a[i]<=108)

输出描述

一行表示答案。

示例1

输入

10
0 1 2 3 4 5 6 7 8 9

输出

20

题解

知识点:二分,数学。

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

1i<jnh(ai,aj)=1i<jnbit(ai+aj)bit(ai)=1i<jnbit(ai+aj)1i<jnbit(ai)=1i<jnbit(ai+aj)1in(ni)bit(ai)=1i<jnbit(ai+aj)1i<jn(ni)bit(ai)

其中,1i<jn(ni)bit(ai) 可以在输入时候处理完。

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

时间复杂度 O(nlogn)

空间复杂度 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 @   空白菌  阅读(35)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
点击右上角即可分享
微信分享提示