Sicily 1199.GCD

几道比赛题都是数论题,不会做,只好上网搜,然后自己整理一下。一些解题方法非本人原创。

题目大意:给定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;
}                                 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值