NC 13221. 数码

链接

https://ac.nowcoder.com/acm/problem/13221

题意

给定两个整数 $l$ 和 $r$,对于所有满足 $1 \le l \le x \le r \le 10^9$ 的 $x$ ,记录 $x$ 的所有因数的最高位,求$1\sim 9$ 每个数码出现的次数

思路

我们可以先计算 $1 \sim r$,然后减去 $1 \sim l-1$

因子都是成对出现的,记两个因子为 $a,b(a<b)$ 我们可以枚举 $a(a \le \sqrt{n})$,那么 $a*b$ 在 $1 \sim r$ 的范围内 $b$ 的取值范围为 $[a+1,r/a]$

对于 $b$ 的首位数,我们从低位开始枚举 $1 \sim 9$,设位数为k,首位数为x,则左界是 $\max(a+1,x*10^k)$,右界是 $\min(r/a,(x+1)*10^k-1)$,如果右界 $\ge$ 左界,那么这个区间合法

对于 $a$ 的首位数的个数是 $b$ 的取值范围长度 $+1$,因为 $b>a$ ,而 $a*a$ 也是合法的,需要记录一次

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#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;
}