离散数学中有种名叫“哈斯图”的东西。
在这题中,你们需要计算的是一些正整数在偏序关系“整除”下的哈斯图的边数。用大白话讲,在偏序关系“整除”下的哈斯图,就是把一个个正整数看成一个个图的节点,某些节点之间有边。连边的规则是这样的:对于任意两个正整数a和b(a
现在问题是,给你们2个数L,R(1<=L,R<=1e6)。求由L,L+1,L+2...R这R-L+1个正整数在偏序关系“整除”下的哈斯图的边数。
比如L=1,R=4,节点的组合有(1,2),(1,3),(1,4),(2,3),(2,4),(3,4)。组合(1,2),(1,3),(2,4)可以连边。(1,4)因为中间存在c=2,不符合连边条件。所以当L=1,R=4的时候,这个哈斯图有3条边。
多组输入,不超过1000组数据 每组数据一行,包含2个正整数L和R,中间由空格分开。
每组数据输出一行,包含一个整数表示哈斯图的边数。
1 4 4 10 1 10
3 2 11
例如:
a = 1, b = 2时,倍数为2,是素数倍,此时k= 2,k1 ,k2只能为1和2,但找不出整数c使得 b = k1*c,c = k2 *a同时成立,此种情况可以连边。
a =1, b=3时,倍数为3,是素数倍,此时k= 3,k1 ,k2只能为1和3,但找不出整数c使得 b = k1*c,c = k2 *a同时成立,此种情况可以连边。
a = 1, b = 4时,倍数为4,非素数倍, 此时k = 4,能找出k1 = 2,k2 = 2 ,(此时 c=2) 来使得 b = k1*c,c = k2 *a 同时成立,此种情况便不能连边。
因此,只需要依据p从小到大进行遍历存在L<=a
按照这个思路,我们来解 样例[1,10] (即 L=1,R=10)
当P = 2时,(a, b) = {(1,2), (2,4), (3,6), (4,8), (5,10)} R/ P - L +1 = 5个。
当P = 3时,(a, b) = {(1, 3), (2, 6), (3,9)} R/ P - L +1 = 3个。
当P = 5时,(a, b) = {(1, 5), (2,10)} R/ P - L +1= 2个。
当P = 7时,(a, b) = {(1,7)} R/ P - L +1 =1个。
当P = 11时,P都大于R了,显然后面都不会存在了。
因此 答案是 5+3+2+1 = 11.
对于在P确定时,求该种情况下的个数t时,t = (R / P) - (L - 1)是这样来的: 当R/P>=L时,就是能连边的条件。例如样例[4,10],P = 2时,a = 1,2,3,4,5(有5个能连边),但a要大于等于左边界,故a只能取4和5,即剔除了比L小的情况。这就是计算a在[1,10]中的个数R/P,再剔除掉a在[1,3]范围内的个数(L-1)。
代码如下:
#include
using namespace std;
int ans,l,r,p[1000010];
bool boo[1000010];
int main()
{
//预处理求出1e6内的素数
for (int i = 2 ; i <= 1000000; i ++)
if (!boo[i])
for (int j = i+i; j <= 1000000; j += i)
boo[j] = true;
for (int i = 2 ; i <= 1000000; i ++)
if (!boo[i])
p[++ p[0]] = i;
// p[i] 储存的是第i个素数 ,p[0]储存的是总共的素数个数
for ( ; scanf("%d%d",&l,&r) != EOF; ){
ans = 0;
int t;//遍历每个素数情况下的个数,如p = 2时,t=5
for (int i = 1; i <= p[0]; i ++){
int t = r/p[i];
if (t >= l) {
ans += t-l+1;
}
// 最大可除数字减去左界就是当前质数的可被除的数量
else break;
}
printf("%d\n",ans);
}
return 0;
}