链接:https://ac.nowcoder.com/acm/problem/14380
来源:牛客网
题目描述
** 给一个数组{a},定义 h(a,b)为在十进制下 a + b 与 a 的位数差,求 ,0的位数为1。 **
看到这道题,第一感觉数学问题;不过既然标签为二分,那就只能往二分靠;∑h(a,b),分开写;
这里函数h(x)指的是x的位数;
n=2时,h(a1+a2)-h(a1);
n=3时,h(a1+a2)-h(a1),h(a1+a3)-h(a1),h(a2+a3)-h(a2)
以上可以看出,h(a1+a2)+h(a1+a3)+h(a2+a3)-(2*h(a1)+h(a2));
拆开之后可以看出,ai+aj是每个数都相加一遍;a1+a2,a1+a3,...a1+an; a2+a3,a2+a4...a2+an;...
再看题目,暴力一定超时;而我们所需求的只是是ai+aj的位数,从题目中可以看出,位数最大为9;所以我们可以将数组排序(ai+aj与数组顺序无关,因为每个数都要相加一遍),对于一个数ai,枚举位数j从h(a[i])~h(a[i]+a[n]),在数组中二分查找值为k使a[i]+k的位数为j的最大位置;
看代码吧:
#include<bits/stdc++.h> using namespace std; #define ll long long ll a[120000],n; ll h(ll x)//判断x的位数 { ll cnt=0,k=x; if(x==0) return 1; else{ while(x) { cnt++; x/=10; } } return cnt; } int main() { cin>>n; ll max1=0,ans=0,mmax=0;//max1为需要减去的部分的和,ans为a[i]+a[j],mmax为数组最大值 for(ll i=1;i<=n;i++) cin>>a[i],h(a[i]),mmax=max(mmax,a[i]),max1+=h(a[i])*(n-i); sort(a+1,a+1+n); for(int i=1;i<n;i++)//枚举从1~n-1 { ll last=i; for(int j=h(a[i]);j<=h(a[i]+mmax);j++)//枚举位数j;例如,当j为1时,最大满足的位置为k,则last记为k;当j为2时,最大满足位置为h,则满足j为2的个数为(h-last)个 { ll l=i+1,r=n;//因为,j>i,所以l从i+1开始 while(l<r) { ll mid=(l+r)/2; if(h(a[mid]+a[i])>j) r=mid-1; else l=mid+1; } if(h(a[l]+a[i])>j) l-=1; ans+=(l-last)*j;//有l-last个数的位数为j last=l; } } cout<<ans-max1; }