GCD
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2836 Accepted Submission(s): 1479
Problem Description
The greatest common divisor GCD(a,b) of two positive integers a and b,sometimes written (a,b),is the largest divisor common to a and b,For example,(1,2)=1,(12,18)=6.
(a,b) can be easily found by the Euclidean algorithm. Now Carp is considering a little more difficult problem:
Given integers N and M, how many integer X satisfies 1<=X<=N and (X,N)>=M.
(a,b) can be easily found by the Euclidean algorithm. Now Carp is considering a little more difficult problem:
Given integers N and M, how many integer X satisfies 1<=X<=N and (X,N)>=M.
Input
The first line of input is an integer T(T<=100) representing the number of test cases. The following T lines each contains two numbers N and M (2<=N<=1000000000, 1<=M<=N), representing a test case.
Output
For each test case,output the answer on a single line.
Sample Input
3
1 1
10 2
10000 72
Sample Output
1
6
260
题意:求gcd(i,n)>=m的个数( 1 <= i <= n )
题解:起初想的是 n%i==0 ans+=n/i 之类的 但是会有很多重复的 只会基本的容斥原理 感觉太麻烦,也不会写。
正解是 若n%a==0 n=a*b 那么gcd(n,i)=a i=a*k k与b互质 如果不互质的话gcd就不为a 所以ans+=euler(b) 然后折半枚举 因为除一下会出来两个因数。
那么为什么这么写就没有重复的 难道没有 这种情况吗 n=a*b ,i=a*c c属于与b互质的集合 n=c*b' , i=c*a a属于与b'互质的集合( a!=c) a*c就被算了两次吗?
自己可以试着证明一下 假设上述是成立的 那么a与c都是n的因子 n可以写成 n=p1^2 * p2^2 * p3^1 与n/a互质的集合中有n的因子 说明a占用了n至少一个素因子的全部次幂
那么c只可能是被占用的那个素因子的次幂。比如n=2*2*3*3*5 a=2*2 与n/a互质的数中有n的因子(c)2 和 4。那么与n/c的数中不可能包含a。 加设c=2 那么n/c=2*3*3*5 不存在
假设c=4 与a相等 是同一种情况。
综上,没有重复的元素。
AC代码
#include <stdio.h> #include <math.h> #include <string.h> #include <stdlib.h> #include <iostream> #include <sstream> #include <algorithm> #include <string> #include <queue> #include <map> #include <vector> #include <set> #include <utility> #include <stack> using namespace std; const int maxn = 2e5+50,inf = 0x3f3f3f3f, mod = 998244353; const double epx = 1e-6; const double PI = acos(-1.0); typedef long long ll; ll euler(ll n) //返回euler(n) { ll res=n,a=n; for(ll i=2; i*i<=a; i++) { if(a%i==0) { res=res/i*(i-1);//先进行除法是为了防止中间数据的溢出 爆int while(a%i==0) a/=i; } } if(a>1) res=res/a*(a-1); return res; } int main() { ll t,n,m; cin>>t; while(t--) { cin>>n>>m; ll ans=0; for(ll i=1;i*i<=n;i++) { if(n%i==0) { if(i>=m) ans+=euler(n/i); if(n/i>=m&&i!=n/i) ans+=euler(i); } } cout<<ans<<endl; } }
如有错误 请大佬 指正~.~