Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 7013 Accepted Submission(s): 2580
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; }