http://acm.hdu.edu.cn/showproblem.php?pid=1695
题意:求 1~b 和 1~ d 有 多少对 数 的 gcd(x,y) = k ?
x = 5 y=7 和 x= 7,y = 5 被认为是 同一种。
题解:
如果两个数的 最大 公约数 是 k 的 话 ,那么 x/k 与 y /k 是 互质的。
所以 原题 可以转化为 求 1~b/k 和 1~d/k 有 多少对 互质的 数。
假设 b = b/k,d= d/k ,b<d
1:对于 1~b 我们可以 利用 欧拉函数 求 其 欧拉函数值 。
定义小于n且和n互质的数构成的集合为Zn,称呼这个集合为n的完全余数集合。
显然,对于素数p,φ(p)= p -1.对于两个素数p、q,他们的乘积n = pq 满足φ(n) =(p-1)(q-1)
证明:对于质数p,q,满足φ(n) =(p-1)(q-1)
考虑n的完全余数集Zn = { 1,2,....,pq -1}
而不和n互质的集合由下面三个集合的并构成:
1) 能够被p整除的集合{p,2p,3p,....,(q-1)p} 共计q-1个
2) 能够被q整除的集合{q,2q,3q,....,(p-1)q} 共计p-1个
3) {0}
很显然,1、2集合中没有共同的元素,因此Zn中元素个数 = pq - (p-1 + q- 1 + 1) = (p-1)(q-1)
上式中黑体的1是它本身,因为是小于它且和它互质的数,所以当然必须减去自身了。
欧拉函数的定义:E(k)=([1,n-1]中与n互质的整数个数).因为任意正整数都可以唯一表示成如下形式:
k=p1^a1*p2^a2*……*pi^ai;(即分解质因数形式)
可以推出:E(k)=(p1-1)(p2-1)……(pi-1)*(p1^(a1-1))(p2^(a2-1))……(pi^(ai-1))
=k*(p1-1)(p2-1)……(pi-1)/(p1*p2*……pi);
=k*(1-1/p1)*(1-1/p2)....(1-1/pk)
/*在程序中利用欧拉函数如下性质,可以快速求出欧拉函数的值(a为N的质因素)
若(N%a==0 && (N/a)%a==0) 则有:E(N)=E(N/a)*a;
若(N%a==0 && (N/a)%a!=0) 则有:E(N)=E(N/a)*(a-1);
*/
2 #include<cstring>
3 #include<cmath>
4 #include<iostream>
5 #include<algorithm>
6 #include<set>
7 #include<map>
8 #include<queue>
9 #include<vector>
10 #include<string>
11 #define inf 0x7fffffff
12 #define maxn 160000
13 #define CL(a,b) memset(a,b,sizeof(a))
14 #define ll long long
15 #define mx 100010
16 using namespace std;
17
18
19 bool f[maxn] ;
20 ll phi[maxn] ;//记录欧拉函数值
21 ll prim[maxn] ;
22 vector<ll>g[maxn];
23 void init()// 素数筛选 及求 欧拉函数值
24 {
25 ll num = 0 ,i,j;
26
27 phi[1] = 1 ;
28
29 CL(f,false) ;
30
31 for(i = 2 ; i <= 100000;i++)
32 {
33
34 if(f[i] == false)
35 {
36 prim[num++] = i;
37 phi[i] = i - 1 ;
38 }
39 for(j = 0;j< num&&prim[j]*i <= 100000;j++)
40 {
41 f[i*prim[j]] = true ;
42 if(i%prim[j] == 0)
43 {
44 phi[i*prim[j]] = phi[i] *prim[j] ;
45
46 }
47 else
48 phi[i*prim[j]] = phi[i]*(prim[j] - 1) ;
49
50 }
51 }
52
53
54
55 for(ll x = 1 ; x <= 100000;x++)//找出所有数的 质因子
56 {
57
58 ll tmp = x;
59 for(i = 0 ;prim[i] *prim[i] <= tmp ;i++)
60 {
61 if(tmp % prim[i] == 0)
62 {
63 g[x].push_back(prim[i]) ;
64
65 while(tmp%prim[i] == 0)tmp/=prim[i] ;
66 }
67
68
69 if(tmp == 1) break ;
70 }
71
72 if(tmp > 1)g[x].push_back(tmp) ;
73 }
74 }
75
76
77 ll dfs(ll x,ll b,ll now)//容斥原理
78 {
79 ll res = 0 ;
80 ll i = 0 ;
81 for(i = x; i < g[now].size();i++ )
82 res = res + b/g[now][i] - dfs(i+1,b/g[now][i],now) ;
83
84 return res ;
85 }
86 int main()
87 {
88 int T ,i;
89 init() ;
90 scanf("%d",&T);
91 int cas = 0 ;
92 ll a,b,c,d ,k;
93 while(T--)
94 {
95 scanf("%I64d%I64d%I64d%I64d%I64d",&a,&b,&c,&d,&k) ;
96
97 if(b > d ) swap(b,d) ;
98
99 if(k == 0|| k>b||k>d)
100 {
101 printf("Case %d: 0\n",++cas);
102 continue ;
103 }
104
105 b = b/k ;
106 d = d/k ;
107 ll ans = 0 ;
108 for(i = 1; i <= b;i++)
109 ans+=phi[i] ;
110 for(i = b+1; i <= d;i++)
111 {
112
113 ans=ans + b - dfs(0,b,i);
114
115 }
116
117
118 printf("Case %d: %I64d\n",++cas,ans) ;
119
120
121
122 }
123
124 }