GCD
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 7013 Accepted Submission(s): 2580
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.
2 1 3 1 5 1 1 11014 1 14409 9
Case 1: 9 Case 2: 736427HintFor 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).
题意:给两个区间[a,b]和[c,d] 让你求出有多少个数对(x,y)【x属于区间[a,b] y属于区间[c,d] 且 (x,y) 和 (y,x)算一个数对】满足gcd(x,y)== k 。
分析:转化区间n = b / k, m = d / k。 是问题变为求区间[1, n] 和[1, m] 里面所有不重复的质数对(x,y)【x属于[1,n] 且y属于[1,m]】。
实现:我们不妨假设n <= m,这样就需要分两种情况求解 1,x属于区间[1,n] 且 y属于区间[1,n] ;2,x属于区间[1,n] 且 y属于区间[n+1,m]。
情况1:对于x属于区间[1,n] 和 y属于区间[1,n]里面的所有不重复质数对(x,y)的数目 就为n个数的欧拉函数之和。
为什么? 我们从x看起,因为数对(x,y) 与 (y,x)是同一数对,因此我们可以只求x < y 的数对之和。 这样在x < y的前提,当x取区间[1,n]里面的任意一值r时,那么成立的数对就为r的欧拉函数,类似的,其它值也一样,因此答案即为所有值的欧拉函数之和。好好体会。
情况2:容斥原理,不用多说了吧,枚举每个y (n+1 <= y <= m),求区间[1,n]里面与当前y互质的个数 ,累加即可。
代码:
#include <cstdio>
#include <cstring>
#include <cmath>
#define LL long long
#define MAX 100000+10
using namespace std;
LL eu[MAX];//eu[i]存储区间[1到 i ]里面的所有不重复质数对数目
int p[100], q;//质因子分解用到
void euler()
{
int i, j;
eu[1] = 1;
for(i = 2; i < MAX; i++)
{
if(!eu[i])
{
for(j = i; j < MAX; j += i)
{
if(!eu[j]) eu[j] = j;
eu[j] = eu[j] * (i-1) / i;
}
}
eu[i] += eu[i-1];
}
}
void getp(int n)//求n的质因子
{
int i;
q = 0;
for(i = 2; i*i <= n; ++i)
{
if(n % i == 0)
{
p[q++] = i;
while(n % i == 0)
n /= i;
}
}
if(n > 1) p[q++] = n;
}
int nop(int m)//求 1到m里面 与当前n互质的数 的个数
{
int top = 0;
int i, j, t;
int que[100000];
que[top++] = -1;
for(i = 0; i < q; i++)
{
t = top;
for(j = 0; j < t; ++j)
{
que[top++] = que[j] * p[i] * (-1);
}
}
int sum = 0;
for(i = 1; i < top; i++)
sum += m/que[i];
return sum;
}
int main()
{
int t;
int i, j = 1;
int a, b, c, d, k;
int n, m;
euler();
scanf("%d", &t);
while(t--)
{
scanf("%d%d%d%d%d", &a, &b, &c, &d, &k);
if(k == 0)
{
printf("Case %d: 0\n", j++);
continue;
}
n = b / k;
m = d / k;
if(n > m)//n为小 m为大
{
a = n;
n = m;
m = a;
}
LL ans = eu[n];//区间[1-n]里面的所有不重复质数对
for(i = n+1; i <= m; i++)
{
getp(i);//求i的质因子
ans += n-nop(n);//求区间[1-n] 里面有多少个数与 i 互质
}
printf("Case %d: %lld\n", j++, ans);
}
return 0;
}