hdu 1965 (莫比乌斯函数 莫比乌斯反演)
GCD
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 9942 Accepted Submission(s): 3732
Problem Description
Given 5 integers: a, b, c, d, k, you're to find x in a...b, y in c...d that GCD(x, y) = k. GCD(x, y) means the greatest common divisor of x and y. Since the number of choices may be very large, you're only required to output the total number of different number pairs.
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.
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.
Input
The input consists of several test cases. The first line of the input is the number of the cases. There are no more than 3,000 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.
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.
Output
For each test case, print the number of choices. Use the format in the example.
Sample Input
2
1 3 1 5 1
1 11014 1 14409 9
Sample Output
Case 1: 9
Case 2: 736427
Hint
For 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).
Source
Recommend
此题算是莫比乌斯反演的经典题。
虽然上面说了把a和c当作1 ,但我们还是把它当做任意数来做。
对于求(a,b) (c,d)上对应的最大公约数为k这类题,先用容斥原理分为四种:(1,b)与(1,d);(1,c-1)与(1,b);(1,a-1)与(1,d);
对于每种情况,假设是(1,n)与(1,m)这两个区间(n<m)。
那这两个区间gcd(x,y)>=k的有(n/k)*(m/k)个。
若要求最大公约数为k,那么求得便是(n/k)与(m/k)中互质的数的个数。
接下来就用莫比乌斯函数求这些互质的数的个数了。
其中我还加入了分段优化。
最后一步就是去重了,题目说想 G(x,y)==G(y,x),所以要把(a,b) (c,d)里重叠的部分多余的去掉。
具体【传送门】
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdlib> 5 #define clr(x) memset(x,0,sizeof(x)) 6 #define LL long long 7 using namespace std; 8 int prime[100010],inf[100010],mu[100010],sum[100010]; 9 long long solve(int n,int m); 10 void mobius(); 11 int main() 12 { 13 int T; 14 scanf("%d",&T); 15 int a,b,c,d,k,minx,maxx; 16 LL ans; 17 mobius(); 18 for(int ii=1;ii<=T;ii++) 19 { 20 scanf("%d%d%d%d%d",&a,&b,&c,&d,&k); 21 if(k == 0) 22 { 23 printf("Case %d: 0\n",ii); 24 continue; 25 } 26 ans=solve(b/k,d/k) - solve((a-1)/k,d/k) - solve(b/k,(c-1)/k) + solve((a-1)/k,(c-1)/k); 27 if((maxx=max(a,c))<(minx=min(b,d))) 28 ans=ans-(solve(minx/k,minx/k)-solve((maxx-1)/k,minx/k)*2+solve((maxx-1)/k,(maxx-1)/k))/2; 29 printf("Case %d: %lld\n",ii,ans); 30 } 31 return 0; 32 } 33 void mobius() 34 { 35 clr(inf); 36 clr(prime); 37 clr(sum); 38 clr(mu); 39 mu[1] = 1; 40 inf[1]=inf[0]=1; 41 int tot = 0; 42 for(int i = 2; i <= 100000; i++) 43 { 44 if( !inf[i] ) 45 { 46 prime[tot++] = i; 47 mu[i] = -1; 48 } 49 for(int j = 0; j < tot; j ++) 50 { 51 if( i * prime[j] > 100000) break; 52 inf[i * prime[j]] = true; 53 if( i % prime[j] == 0) 54 { 55 mu[i * prime[j]] = 0; 56 break; 57 } 58 else 59 { 60 mu[i * prime[j]] = -mu[i]; 61 } 62 } 63 } 64 for(int i = 1;i <= 100000;i++) 65 sum[i] = sum[i-1] + mu[i]; 66 } 67 LL solve(int n,int m) 68 { 69 LL ans = 0; 70 if(n > m)swap(n,m); 71 for(int i = 1, la = 0; i <= n; i = la+1) 72 { 73 la = min(n/(n/i),m/(m/i)); 74 ans += (LL)(sum[la] - sum[i-1])*(n/i)*(m/i); 75 } 76 return ans; 77 }