1.这题要取[l,r]之间的数的约数的首位数字,如果采用一个一个数枚举求约数的话,
数据范围很大肯定会超时,所有就得先想一个方法优化时间复杂度。
一个数学方法:N/K等于1-N中有多少个数的约数含有k
然后在通过前缀和可以得到:s[1,r]-s[1,l-1]
2.在通过整除数论来得到最后答案
整除数论:1-n的数被n整除,最后会变成连续的区间,其中的区间值相同,这正好与上面的数学方法相对应。
然后处理先区间边界问题,确定左边界l,右边界r=(n/(n/l),这个记住就好了,证明
太难了。
3.只求约数的最高位,然后只需要枚举区间就行了,最高位为1的区间[1,1],[10,19],
[100,199],[1000,1999]......
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
 
using namespace std;
 
typedef long long LL;
 
int pow[10];
 
LL slove(LL n,int k)
{
    LL ans=n/k;
    for(int i=1;i<9;i++)
    {
        LL st=k*pow[i],ed=st+1*pow[i]-1;
        ed=min(n,ed);
        for(LL l=st;l<=ed;l=n/(n/l)+1)
        {
            LL r=min(ed,n/(n/l));
            ans+=(r-l+1)*(n/l);
        }
    }
    return ans;
}
 
int main()
{
    int l,r;
    cin>>l>>r;
     
    pow[0]=1;
    for(int i=1;i<=9;i++) pow[i]=pow[i-1]*10;
     
    for(int i=1;i<=9;i++)
        cout<<slove(r,i)-slove(l-1,i)<<endl;
    return 0;
}