题目链接传送门
知识点
二分
题解
题解摘自https://www.cnblogs.com/wsy107316/p/12334575.html
按从大大到小排好的数组里,a[i]会与后面较小的数相加求位数后再累加,
即计算∑0≤i<j≤n bit(a[i]+a[j]) 的值
验证可知一个数k加上一个小于等于k的数后,其数位要么+1(产生进位),要么不加(没有产生进位)
由于数组是降序排序的,所以必然存在一个临界点,使得a[i]加上临界点前的数一定会进位,加上临界点后的数(小于临界点)一定不会进位。
所以对于a[i]而言,计算∑i<j≤n bit(a[i]+a[j]) 只需找到从a[i+1]~a[n]中的会使其进位的区间 【i+1,r】即可。
查找临界点r 时 若直接遍历会超时,因为外面还套了个循环,所以时间复杂度是n2
这里采用二分,一层查询是logn ,总体时间复杂度是 nlogn
二分查临界点的代码我纠结了很久,最后终于搞明白了,写了篇博客二分搜索临界点
代码
#include<iostream>
#include <algorithm>
using namespace std;
const int maxn = 1e5+5;
int a[maxn];
int bit(int x){
if(x==0)return 1;
int ans=0;
while(x){
ans++;
x/=10;
}
return ans;
}
bool cmp(int x,int y){return x>y;}
int main(){
int n;
long ans=0;
cin>>n;
for(int i=0;i<n;i++){
cin>>a[i];
ans-=(n-1-i)*bit(a[i]);
}
sort(a,a+n,cmp);
for(int i=0;i<n-1;i++){
int now = bit(a[i]);
int l=i+1,r=n-1;
while(l<=r){
int mid=(l+r)>>1;
if(bit(a[i]+a[mid])>now) l=mid+1;
else r=mid-1;
}
ans+=(r-i)*(now+1)+(n-1-r)*now;
}
cout<<ans;
}