位数差 题解

题目链接传送门

知识点

二分

题解

摘自https://www.cnblogs.com/wsy107316/p/12334575.html
题解摘自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;
}     


发布了15 篇原创文章 · 获赞 14 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/fuckguidao/article/details/104965592