数论分块,那么咋分呢?我们先手动一发。
比如此时r=66.我们要求1的出现次数那么就是1,[10,20)
66/1 = 66 , 而66/66 = 1,代表从[1,1]只有1个数最高位为1
66/10=6,66/6=10,代表从[10,10]有1个数高位为1
66/11=6,66/6=11,代表[11,11]有1个数高位为1
66/12=5,66/5=13,代表[12,13]有2个数高位为1
66/14=4,66/4=16,代表[14,16]有3个数高位1
66/17=3,66/3=22,22>20代表[17,20)有3个高位1
至此我们就可以看出了如何去分。要求出[l,r]中我们就换成求出 [i,r]-[i,l-1] (1<=i<=9),那么就模拟一遍过程就可以了。
#include <iostream> #include <algorithm> #include <cstdio> #include <set> #include <sstream> #include<string> #include<queue> #include<stack> #include<map> #include<cmath> #include<cctype> #include<cstring> #include<cstdlib> #define MAXX 100005 #define SIS std::ios::sync_with_stdio(false) #define ll long long #define INF 0x3f3f3f3f //#include<bits/stdc++.h> using namespace std; const int MAX =1e5+6; const double PI = 3.14159265359; //const int mod = 1e9 + 7; ll a[MAX]; ll sum[MAX]; ll solve(ll r,ll x) { ll ans=r/x; ll st=x*10,en=min(r,x*10+9);///先求出左右区间 for(;st<=r;st*=10,en=en*10+9) { ll k=min(en,r);///在边界内 for(ll i=st;i<=k;) { ll sum=r/i; ll mx=min(r/sum,k); ans+=sum*(mx-i+1); i=mx+1;///更新区间 } } return ans; } int main() { SIS; ll l,r; cin>>l>>r; for(int i=1;i<=9;i++) { cout<<solve(r,i)-solve(l-1,i)<<endl; } }