链接
https://ac.nowcoder.com/acm/problem/13221
题意
给定两个整数 l l l 和 r r r,对于所有满足 1 ≤ l ≤ x ≤ r ≤ 1 0 9 1 \le l \le x \le r \le 10^9 1≤l≤x≤r≤109 的 x x x ,记录 x x x 的所有因数的最高位,求 1 ∼ 9 1\sim 9 1∼9 每个数码出现的次数
思路
我们可以先计算 1 ∼ r 1 \sim r 1∼r,然后减去 1 ∼ l − 1 1 \sim l-1 1∼l−1
因子都是成对出现的,记两个因子为 a , b ( a < b ) a,b(a<b) a,b(a<b) 我们可以枚举 a ( a ≤ n ) a(a \le \sqrt{n}) a(a≤n),那么 a ∗ b a*b a∗b 在 1 ∼ r 1 \sim r 1∼r 的范围内 b b b 的取值范围为 [ a + 1 , r / a ] [a+1,r/a] [a+1,r/a]
对于 b b b 的首位数,我们从低位开始枚举 1 ∼ 9 1 \sim 9 1∼9,设位数为k,首位数为x,则左界是 max ( a + 1 , x ∗ 1 0 k ) \max(a+1,x*10^k) max(a+1,x∗10k),右界是 min ( r / a , ( x + 1 ) ∗ 1 0 k − 1 ) \min(r/a,(x+1)*10^k-1) min(r/a,(x+1)∗10k−1),如果右界 ≥ \ge ≥ 左界,那么这个区间合法
对于 a a a 的首位数的个数是 b b b 的取值范围长度 + 1 +1 +1,因为 b > a b>a b>a ,而 a ∗ a a*a a∗a 也是合法的,需要记录一次
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=20;
ll a[N],b[N];
int high(int x) {
while(x/10) x/=10;
if(x==0) return 1;
else return x;
}
void calc(int x,ll *a) {
for(int i=1;i*i<=x;i++) {
int l=i+1,r=x/i;
for(int j=1;j<=r;j*=10)
for(int k=1;k<=9;k++) {
int x=max(j*k,l);
int y=min(j*(k+1)-1,r);
if(y-x>=0) a[k]+=y-x+1;
}
a[high(i)]+=r-i+1;
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int l,r;
cin>>l>>r;
calc(r,a);
calc(l-1,b);
for(int i=1;i<=9;i++) cout<<a[i]-b[i]<<endl;
return 0;
}