GCD
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1567 Accepted Submission(s): 751
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.
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
题目大意:
数据量太大,用常规方法做是行不通的。后来看了别人的解题报告说,先找出N的约数x,
并且gcd(x,N)>= M,结果为所有N/x的欧拉函数之和。
因为x是N的约数,所以gcd(x,N)=x >= M;
设y=N/x,y的欧拉函数为小于y且与y互质的数的个数。
设与y互质的的数为p1,p2,p3,…,p4
那么gcd(x* pi,N)= x >= M。
也就是说只要找出所有符合要求的y的欧拉函数之和就是答案了。
至于为何用ans+=Euler(n/i0而不是直接加n/i,这便是为了查重,防止出现重复
只加满足gcd(k*x,n)==x的个数,不过如果直接遍历找约数遍历的量太大,同样会
TLE,因此可以把区间右坐标变成sqrt(n),同时判断i和n/i即可,特别注意num*num=n
的情况要单独处理。
代码:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
typedef long long LL;
int kase=0;
LL Euler(LL n)
{
LL ans=n;
for(int i=2;i*i<=n;i++)
{
if(n%i==0)
{
ans-=ans/i;
while(n%i==0) n/=i;
}
}
if(n>1) ans-=ans/n;
return ans;
}
int main()
{
int t;
cin>>t;
__int64 n,m;
while(t--)
{
kase=0;
scanf("%I64d%I64d",&n,&m);
int num=(int)sqrt(n+0.5);
//cout<<num<<endl;
for(int i=1;i<num;i++)
{
if(n%i==0)
{
if(n/i>=m)
kase+=Euler(i);
if(i>=m)
kase+=Euler(n/i);
}
}
//cout<<kase<<endl;
// cout<<Euler(100)<<endl;
if(num*num==n&&num>=m) kase+=Euler(num);
cout<<kase<<endl;
}
return 0;
}