题意:
给定T组数据,每组数据N,M
询问有多少个 1<=x<=n gcd(n,x)>=m
思路:
以前只是知道欧拉函数(当然求还是靠板子)有用来求从1-n-1中 与n互质的个数,这个题是一个应用
欧拉函数是求比 euler(q) 所有比q小的与q互素的数。那么如果得到有ans个与q互素的数字,乘以我们枚举的d就会得到ans个数字,这ans个数字中的每一个都满足我们所需要的:
gcd(x,n)==d
(x,n)>=是题目要求->
设 gcd(x,n)==d p 与 q 分别是 在等式1.2中d的系数
x= p * d
n=q * d;
其中d>=m
当我们枚举确定了d之后,自然可以求出q, 因为我们当前确定gcd(x,n)==d 所以 q与p一定互质。因此对于q的欧拉函数个数即使当前d下 x的可以取值个数。依次枚举
注意:
如果我们从m->n枚举会TLE。
优化:
如果我们确定了一个d,我们可以得知d的满足条件,同时如果d>=m 那么求他的系数n/d的欧拉函数
反之-->如果n/d>=m 那么他的系数d也必定满足条件。求i的欧拉函数即可
具体见代码
#include <iostream>
#include <stdio.h>
using namespace std;
typedef long long ll;
ll n,m;
ll res=0;
void euler(ll x)
{
ll ans;
ans=x;
for(int i=2; i*i<=x; ++i)
{
if(x==1)
break;
if(x%i==0)
{
ans=ans/i*(i-1);
while(x%i==0)
x/=i;
}
}
if(x!=1)
{
ans=ans/x*(x-1);
}
res+=ans;
return ;
}
int main()
{
int T;
cin>>T;
while(T--)
{
cin>>n>>m;
res=0;
for(ll i=1;i*i<=n ;i++ )
{
if(n%i)
continue;
if(i>=m)
euler(n/i);
if((n/i)!=i&&(n/i)>=m)
euler(i);
//euler(i);
// printf("%lld\n",res);
}
cout<<res<<endl;
}
return 0;
}