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;
}