![BZOJ 2301: [HAOI2011]Problem b (莫比乌斯反演) BZOJ 2301: [HAOI2011]Problem b (莫比乌斯反演)](https://image.shishitao.com:8440/aHR0cHM6Ly9ia3FzaW1nLmlrYWZhbi5jb20vdXBsb2FkL2NoYXRncHQtcy5wbmc%2FIQ%3D%3D.png?!?w=700&webp=1)
2301: [HAOI2011]Problem b
Time Limit: 50 Sec Memory Limit: 256 MB
Submit: 436 Solved: 187
[Submit][Status]
Description
对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函数为x和y的最大公约数。
Input
第一行一个整数n,接下来n行每行五个整数,分别表示a、b、c、d、k
Output
共n行,每行一个整数表示满足要求的数对(x,y)的个数
Sample Input
2
2 5 1 5 1
1 5 1 5 2
Sample Output
14
3
HINT
100%的数据满足:1≤n≤50000,1≤a≤b≤50000,1≤c≤d≤50000,1≤k≤50000
Source
HOME Back
思路可以参考下面的链接:
http://www.cnblogs.com/zhsl/p/3269288.html
http://wenku.baidu.com/view/fbe263d384254b35eefd34eb.html
分段优化。
/* ***********************************************
Author :kuangbin
Created Time :2013/8/21 20:19:04
File Name :F:\2013ACM练习\专题学习\数学\莫比乌斯反演\BZOJ2301.cpp
************************************************ */ #include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <time.h>
using namespace std;
const int MAXN = ;
bool check[MAXN+];
int prime[MAXN+];
int mu[MAXN+];
void Moblus()
{
memset(check,false,sizeof(check));
mu[] = ;
int tot = ;
for(int i = ; i <= MAXN; i++)
{
if( !check[i] )
{
prime[tot++] = i;
mu[i] = -;
}
for(int j = ; j < tot; j ++)
{
if( i * prime[j] > MAXN) break;
check[i * prime[j]] = true;
if( i % prime[j] == )
{
mu[i * prime[j]] = ;
break;
}
else
{
mu[i * prime[j]] = -mu[i];
}
}
}
}
int sum[MAXN+];
//找[1,n],[1,m]内互质的数的对数
long long solve(int n,int m)
{
long long ans = ;
if(n > m)swap(n,m);
for(int i = , la = ; i <= n; i = la+)
{
la = min(n/(n/i),m/(m/i));
ans += (long long)(sum[la] - sum[i-])*(n/i)*(m/i);
}
return ans;
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
Moblus();
sum[] = ;
for(int i = ;i <= MAXN;i++)
sum[i] = sum[i-] + mu[i];
int a,b,c,d,k;
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
long long ans = solve(b/k,d/k) - solve((a-)/k,d/k) - solve(b/k,(c-)/k) + solve((a-)/k,(c-)/k);
printf("%lld\n",ans);
}
return ;
}