GCD
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2346 Accepted Submission(s): 850
Please notice that, (x=5, y=7) and (x=7, y=5) are considered to be the same.
Yoiu can assume that a = c = 1 in all test cases.
Each case contains five integers: a, b, c, d, k, 0 < a <= b <= 100,000, 0 < c <= d <= 100,000, 0 <= k <= 100,000, as described above.
题目大意:
给你a, b, c, d, k; 找出这样的一队 x, y, 使得 gcd(x , y) = k, 并且x ∈[1, b], y ∈ [1, d], 问有多少对符合要求的(x, y)。
------------------------------------------------------------------------------
思路: gcd(x, y) == k 说明x,y都能被k整除, 但是能被k整除的未必gcd=k , 必须还要满足互质关系. 问题就转化为了求1~a/k 和 1~b/k间互质对数的问题可以把a设置为小的那个数, 那么以y>x来保持唯一性(题目要求, 比如[1,3] =[3,1] )
接下来份两种情况:
1. y <= a , 那么对数就是 1~a的欧拉函数的累计和(容易想到)
2. y >= a , 这个时候欧拉函数不能用了,怎么做? 可以用容斥原理,把y与1~a互质对数问题转换为y的质数因子在1~a范围内能整除的个数(质数分解和容斥关系),dfs一下即可。
链接:http://acm.hdu.edu.cn/showproblem.php?pid=1695
代码:
#include <iostream>
#include <stdio.h>
#include <memory.h>
#include <vector>
using namespace std;
const int N = 100005;
typedef long long LL;
LL prime[N];
LL phi[N];
bool is_prime[N];
vector<LL> link[N];
void get_phi() //筛法欧拉函数
{
LL i, j, k = 0;
phi[1] = 1;
for(i = 2; i < N; i++)
{
if(is_prime[i] == false)
{
prime[k++] = i;
phi[i] = i-1;
}
for(j = 0; j<k && i*prime[j]<N; j++)
{
is_prime[ i*prime[j] ] = true;
if(i%prime[j] == 0)
{
phi[ i*prime[j] ] = phi[i] * prime[j];
break;
}
else
{
phi[ i*prime[j] ] = phi[i] * (prime[j]-1);
}
}
}
}
void init() //求每一个数的质因数,vector储存
{
LL i, j, k;
for(i = 1; i < N; i++)
{
k = i;
for(j = 0; prime[j]*prime[j] <= k; j++)
{
if(k%prime[j] == 0)
{
link[i].push_back(prime[j]);
while(k%prime[j] == 0)
k /= prime[j];
}
if(k == 1) break;
}
if(k > 1) link[i].push_back(k);
}
}
LL dfs(LL a, LL b, LL cur) //容斥原理计算
{
LL i, k, res = 0;
for(i = a; i < link[cur].size(); i++)
{
k = b/link[cur][i];
res += k - dfs(i+1, k, cur);
}
return res;
}
int main()
{
LL i, a, b, c, d, k, sum, t, zz = 1;
get_phi();
init();
scanf("%I64d", &t);
while(t--)
{
scanf("%I64d %I64d %I64d %I64d %I64d", &a, &b, &c, &d, &k);
if(k == 0 || k > b || k > d)
{
printf("Case %I64d: 0\n", zz++);
continue;
}
if(b > d) swap(b, d);
b /= k;
d /= k;
sum = 0;
for(i = 1; i <= b; i++)
{
sum += phi[i];
}
for(i = b+1; i <= d; i++)
{
sum += b - dfs(0, b, i);
}
printf("Case %I64d: %I64d\n", zz++, sum);
}
return 0;
}