「51nod 1860」BigPrime

我们把所有大于整数 pp 的质数称作大质数。

现在我们要统计区间 [a,b][a,b] 中有多少数其至少有一个约数是大质数。

Constraints

p106p\leq 10^6a109a\leq 10^9ba108b-a\leq 10^8

Solution

先把 22pp 所有质数预处理出来。记第 kk 个质数为 pkp_k。令 f(x,y,b)f(x,y,b) 表示 [x,y][x,y] 中所有质因子不大于 pbp_b 的数个数。

分以下几种情况:

x>yx>yf(x,y,b)=0f(x,y,b)=0

b=0b=0x=1yx=1\leq yf(x,y,b)=1f(x,y,b)=1

x=yx=y 则暴力分解 xx 看是否满足。(可以部分预处理)

ypby\leq p_bf(x,y,b)=yx+1f(x,y,b)=y-x+1

否则 f(x,y,b)=f(x,y,b1)+f(xpb,ypb,b)f(x,y,b)=f(x,y,b-1)+f(\frac{x}{p_b},\frac{y}{p_b},b) (上取整)

最后一种情况的意思是,当前 [x,y][x,y] 中质因子不包含 pbp_b 的数。后一个是至少包含一个 pbp_b 的数,可以把 pbp_b 除下去以后递归求解。

以上是官方题解。

以下是另一种写法,原理基本一致。

f(x,y,c)f(x,y,c) 表示在 (x,y](x,y] 这个区间中所有质因子均不小于 pcp_c 且不大于 pp 的数个数。

枚举第 cc 个及其后面的质数,递归计算 f(xpc,ypc,c)f(\frac{x}{p_c},\frac{y}{p_c},c) 并累加。由于需要特殊处理 11 的情况,当 x=0x=0ansans 初值为 11 。其余处理细节详见代码。

Code

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
33
34
35
36
37
38
39
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define LL long long
using namespace std;
const int N=1e6+5;
int p,a,b,cnt,limit,pri[N];
bool np[N];
int read()
{
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
int f(int x,int y,int c)
{
if(x==y)return 0;
int ans=(x==0);
while(c<=cnt&&1ll*pri[c]*pri[c]<=y)ans+=f(x/pri[c],y/pri[c],c),c++;
ans+=upper_bound(pri+c,pri+cnt+1,y)-upper_bound(pri+c,pri+cnt+1,x);
return ans;
}
int main()
{
p=read();a=read();b=read();
for(int i=2;i<=p;i++)
{
if(!np[i])pri[++cnt]=i;
for(int j=1;i*pri[j]<=p;j++)
{
np[i*pri[j]]=true;
if(i%pri[j]==0)break;
}
}
printf("%d\n",b-a+1-f(a-1,b,1));
return 0;
}