离散数学中有种名叫“哈斯图”的东西。
在这题中,你们需要计算的是一些正整数在偏序关系“整除”下的哈斯图的边数。用大白话讲,在偏序关系“整除”下的哈斯图,就是把一个个正整数看成一个个图的节点,某些节点之间有边。连边的规则是这样的:对于任意两个正整数a和b(a<b)来说,如果b%a==0,并且不存在一个正整数c(a<c<b),使得条件b%c==0和c%a==0同时成立,那么我们就在节点a和节点b之间连一条边。
现在问题是,给你们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
备注:
哈斯图(英语Hasse发音为/ˈhæsə/,德语: /ˈhasə/)、在数学分支序理论中,是用来表示有限偏序集的一种数学图表,它是一种图形形式的对偏序集的传递简约。 具体的说,对于偏序集合(S,≤),把S的每个元素表示为平面上的顶点,并绘制从x到y向上的线段或弧线,只要y覆盖x(就是说,只要x < y并且没有z使得x < z < y)。这些弧线可以相互交叉但不能触及任何非其端点的顶点。带有标注的顶点的这种图唯一确定这个集合的偏序。
解题思路:
比赛的时候看到这道题的时候,我想 卧槽,离散数学的东西哎,我之前没学过,先放放吧。然后到比赛结束也没咋碰这题。
我觉得有些时候,我还是不怎么静下心来分析问题,因为只有分析,你才能找到解决问题的方法。
我在网上看了一下整除的高斯图该怎么画,然后我就按照那样画了画
我们以1,2,3,4,5,6,7,8,9,10为例,我们能得到满足b%a==0,并且不存在一个正整数c(a<c<b),使得条件b%c==0和c%a==0同时成立的边有
1--2 2--4 3--6 4--8 5--10
1--3 2--6 3--9
1--5 2--10
1--7
我们能从中找到一个规律就是 如果a,b 满足b%a==0且不存在正整数c使得 b%c==0&&c%a==0的话,b/a是一个素数,
从上面的这些关系中我们就知道
1--2 2--4 3--6 4--8 5--10 //2
1--3 2--6 3--9//3
1--5 2--10//5
1--7//7
在1到10中,以2为乘积素数的边有5条,以3为乘积的边有3条,以5为乘积的边有2条,以7为乘积的边为1条,这些边,我们可以拿10/素数就能得到。如果我们是从1出发的话,那很好算,只需要拿相应的素数除一下就是个数了,然后我们求和一下。但是如果不是从1出发的尼,比如是从4到10那么对于每一个素数,留下来的边还有
4--8 5--10//2
//3
//5
//7
然而我们知道以2为乘积的边有5条的,留下了2条符合题意的,那么我们就可以知道当你边数大于等于下边界的时候,我们就可以拿这个边数减去(l-1)个 然后累加求和就行了。
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int maxn=1e6+10;
int n,num[maxn],cnt,vis[maxn],l,r;
void find(){
cnt=0;
memset(vis,1,sizeof(vis));
vis[1]=0;
long long i,j;
for(i=2;i<maxn;i++){
if(vis[i]){
num[cnt++]=i;
}
for(j=0;j<cnt&&num[j]*i<maxn;j++){
vis[num[j]*i]=0;
}
}
}
int main(){
int i,j;
find();
while(scanf("%d%d",&l,&r)!=EOF){
int ans=0;
for(i=0;i<cnt;i++){
int k=r/num[i];
if(k>=l) ans+=(k-l+1);
else break;
}
printf("%d\n",ans);
}
return 0;
}