对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函数为x和y的最大公约数
1≤n≤50000,1≤a≤b≤50000,1≤c≤d≤50000,1≤k≤50000
2 2 5 1 5 1 1 5 1 5 2Sample Output
14 3
上叙对于区间最远的端点的理解:
若a为10,x为 4 ,因为 10除以4有余数,所以会存在x在扩大的过程中尽量减少这个余数,很容易知道当x为5的时候刚好没有余数,同时他们的商都是2
最后发现,其实上面叙述的P 其实就是莫比乌斯函数
而莫比乌斯函数反演有两种形式,一般是第二种:
从这两个形式中可以发现莫比乌斯函数的两个应用:
对于一些函数,我们很难直接求他的值,但是很容易求这个函数的倍数或者约数的值
此时我们可以用莫比乌斯反演得到此函数,本题就是这么个道理
#include
#include
#include
using namespace std;
#define MAXN 100000
#define LL long long
bool check[MAXN+10];
int primer[MAXN+10];
int mu[MAXN+10];
int sum[MAXN+10];
void Moblus()
{
memset(check,0,sizeof(check));
mu[1]=1;
int tot=0;
for(int i=2;i<=MAXN;i++){
if(!check[i]){
primer[tot++]=i;
mu[i]=-1;
}
for(int j=0;jm) swap(n,m);
for(int i=1,last;i<=n;i=last+1){
last=min(n/(n/i),m/(m/i));
ans+=(LL)(sum[last]-sum[i-1])*(n/i)*(m/i);
}
return ans;
}
int main()
{
int T;
Moblus();
int a,b,c,d,k;
//freopen("in.txt","r",stdin);
scanf("%d",&T);
while(T--)
{
scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
LL ans=solve(b/k,d/k)-solve((a-1)/k,d/k)
-solve(b/k,(c-1)/k)+solve((a-1)/k,(c-1)/k);
printf("%lld\n",ans);
}
return 0;
}
2 1 3 1 5 1 1 11014 1 14409 9Sample Output
Case 1: 9 Case 2: 736427Hint
For the first sample input, all the 9 pairs of numbers are (1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (2, 3), (2, 5), (3, 4), (3, 5).
本题和上题不同的是,需要去重
(1,2)和(2,1)是一样的
#include
#include
#include
using namespace std;
#define MAXN 1000000
#define LL long long
bool check[MAXN+10];
LL primer[MAXN+10];
LL mu[MAXN+10];
LL sum[MAXN+10];
void Moblus()
{
memset(check,0,sizeof(check));
mu[1]=1;
int tot=0;
for(int i=2;i<=MAXN;i++){
if(!check[i]){
primer[tot++]=i;
mu[i]=-1;
}
for(int j=0;jm) swap(n,m);
for(int i=1,last;i<=n;i=last+1){
last=min(n/(n/i),m/(m/i));
ans+=(LL)(sum[last]-sum[i-1])*((LL)(n/i)*(m/i));
}
return ans;
}
int main()
{
int T;
Moblus();
int a,b,c,d,k,cases=1;
// freopen("in.txt","r",stdin);
scanf("%d",&T);
while(T--)
{
printf("Case %d: ",cases++);
scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
if(k==0){
puts("0");
continue;
}
LL ans=solve(b/k,d/k)-solve((a-1)/k,d/k)
-solve(b/k,(c-1)/k)+solve((a-1)/k,(c-1)/k);
int x=max(a,c);
int y=min(b,d);
if(y>=x){
ans-=solve(y/k,y/k)/2;
ans+=solve(x/k,x/k)/2;
}
printf("%I64d\n",ans);
}
return 0;
}