这种问题一般都是给出限制条件:给你一个数N(N一般很大),使得在1~N之间能够找到X使得X满足GCD(X,N)>=M,然后求解相关问题.
分析:这是一种统计类型的问题.比较容易想到的解法就是枚举GCD(X,N)的值,对于枚举到的某个GCD(X,N)的值d,如果令N=p*d,X=q*d,那么GCD(X,N)=d,一定有p,q互质,又有X<=N,则q<=p,而这样的q的个数正好对应p的欧拉函数,即满足GCD(X,N)=d的X的个数为N/d的欧拉函数值.
应用1:给出N和M,求有多少个X满足1<=X<=N,并且(X,N)>=M.
解题思路:对于这个问题,因为只需要求出满足题意的X的个数,所以可以枚举最大公约数d,而满足gcd(X,N) = d 的X的个数就是N/d的欧拉函数,把这些d对应的N/d的欧拉函数值求和即可。
LL res=0,i;
for(i=1;i*i<=n;i++)
{
if(n%i==0)
{
if(i>=m)
res+=euler(n/i)*i;
if(i*i!=n&&n/i>=m)
res+=euler(i)*(n/i);
}
}
printf("%lld\n",res);
应用2: 给你一个数N,使得在1~N之间能够找到x使得x满足gcd( x , N ) >= M,求解gcd(x,N)的和.
分析:这个题要求gcd(X,N)的和,因为上一题已经求出了满足题意的个数,所以只需要在上一个应用的基础上乘以最大公约数就是最终答案。
LL res=0,i;
for(i=1;i*i<=n;i++)
{
if(n%i==0)
{
if(i>=m)
res+=euler(n/i)*i;
if(i*i!=n&&n/i>=m)
res+=euler(i)*(n/i);
}
}
printf("%lld\n",res);
应用3:给你一个数N,使得在1~N之间能够找到x使得x满足gcd( x , N ) >= M,求解X的和.
分析:这个题和前两个题基本上一样,只需要在枚举最大公约数d时,求出gcd(X,N) = d 的所有X的和即可。根据上面可以得出:满足条件的X个数有euler(N/d)个,所以只需要求出不超过N/d且与N/d互素的那些数的和,然后乘以d就是最大公约数为d时对应的部分结果。而不超过N/d且与N/d互素的那些数的和 = N/d * euler(N/d) / 2,注意当N/d = 1时,结果是1而不是0。了解了这些,就可以解决这个题了。
除了1、2以外,所有数的欧拉函数都是偶数。
如果k <= n 并且 (k,n) = 1, 那么(n-k, n) = 1;
#include
#include
#include
#include
#include
using namespace std;
#define M 1000000007
typedef long long LL;
LL euler(LL n)
{
LL ans=n,i;
for(i=2;i*i<=n;i++)
{
if(n%i==0)
{
ans=ans/i*(i-1);
while(n%i==0)
n/=i;
}
}
if(n>1)
ans=ans/n*(n-1);
return ans;
}
LL euler_sum(LL n)
{
if(n==1)
return 1;
return n*(euler(n))/2;
}
int main()
{
int t;
LL n,m;
scanf("%d",&t);
while(t--)
{
scanf("%lld%lld",&n,&m);
LL res=0,i;
for(i=1;i*i<=n;i++)
{
if(n%i==0)
{
if(i>=m)
{
res+=euler_sum(n/i)*i;
res%=M;
}
if(i*i!=n&&n/i>=m)
{
res+=euler_sum(i)*(n/i);
res%=M;
}
}
}
printf("%lld\n",res);
}
return 0;
}