几道比赛题都是数论题,不会做,只好上网搜,然后自己整理一下。一些解题方法非本人原创。
题目大意:给定N,M,求有多少X<=N满足gcd(N,X)>=M
方法:
(1)欧拉函数。。。这里不再赘述,可以百度。
(2)变形技巧。
分析:
要求L=gcd(N,X)>=M,则L是N的一个因子。可以先求出N的所有因子,将其中大于或等于M的数用数组L[]储存起来。而对于每一个不同的L[i],它所对应的X肯定不一样(哪儿有两个数的最大公约数有两个。。。)。设F(L[i])是每个L[i]所对应的X的个数。所以本题就等于求∑F(L[i])。
要求和,得先对每一个特定的F(L[i])进行分析啊。
L[i]=gcd(M,X),有M/L[i] 和X/L[i] 互质。(为什么互质?如果不互质,L[i]就可以再乘以M/L[i] 和X/L[i] 的约数,而且依然是M和X的公约数,这样L[i] 就不是M和X的最大公约数了)
而X<=M,所以X/L[i] <=M/L[i],那么,有多少个k满足k<= M/L[i],且k与M/L[i] 互质,就对应存在多少个X=k ·L[i]满足题意。
而这一步就交给欧拉函数吧,它专门干这个的。。。。
哎呀,,好绕啊,他们怎么想出来的,,无力。。。
总之大体就是,先求N的因子L,再用欧拉函数求小于M/L[i]与其互质的质数的个数,最后加起来完事。
当然,要注意一些特殊情况了,比如n<m,n==m,m==1或m==0等。
#include<iostream>
using namespace std;
int L[200000];
int Ola(int n)
{
int temp=n;
for(int i=2;i*i<=n;i++)
if(n%i==0)
{
temp=(temp/i)*(i-1);
for(;n%i==0;n/=i);
}
if(n>1) temp=(temp/n)*(n-1);
return temp;
}
int main()
{
int T;
cin>>T;
while(T--)
{
int n,m,number=0;
cin>>n>>m;
if(n<m)
{
cout<<0<<endl;
continue;
}
else if(n==m)
{
cout<<1<<endl;
}
else if(m==1||m==0)
{
cout<<n<<endl;
}
else
{
int count=0;
for(int i=2;i*i<=n;i++)
{
if(n%i==0)
{
L[count++]=i;
if(i*i!=n) L[count++]=n/i;
}
}
for(int i=0;i<count;i++)
{
if(L[i]>=m)
{
number+=Ola(n/L[i]);
}
}
cout<<number+1<<endl;
}
}
return 0;
}