2019级ACM寒假训练第五天(Gcd&&Lcm,快速幂取模)

点击蓝字即可进入林大oj看见原题,原题右侧为题解和点代码提交,林大oj: acm. nefu. edu. cn
最大公约数和最小公倍数
这题没什么。

#include 
using namespace std;
int gcd(int s1,int s2)
{return s2?gcd(s2,s1%s2):s1;
    }
int main()
{
    int a,b,c;
    while(cin>>a>>b)
    {   c=gcd(a,b);
        printf("%d %d\n",c,(a*b)/c);
    }
    return 0;
}

其实C++内置了gcd函数,可以直接使用,即为: __gcd(a,b)

#include 
using namespace std;
int main()
{
    int a,b,c;
    while(cin>>a>>b)
    {   c=__gcd(a,b);
        printf("%d %d\n",c,(a*b)/c);
    }
    return 0;
}

又见GCD
依次判断B的i倍是否符合题意即可

#include 
using namespace std;
int gcd(int s1,int s2)
{return s2?gcd(s2,s1%s2):s1;
    }
int a,b,c;
long t;
int main()
{   while(cin>>a>>b)
     {  for(int i=2;;i++)
          {  t=i*b;
             if(gcd(t,a)==b)
             { printf("%ld\n",t);
               break;
             }
          }
     }

    return 0;
}

多个数的最大公约数
依次求最大公约数即可

#include 
using namespace std;
int gcd(int s1,int s2)
{return s2?gcd(s2,s1%s2):s1;
    }
int n;
long long a[20],c;
int main()
{   while(cin>>n)
    {  for(int i=0;i<n;i++)
           cin>>a[i];
       c=gcd(a[0],a[1]);
       for(int i=2;i<n;i++)
         c=gcd(c,a[i]);
       printf("%lld\n",c);
      }

    return 0;
}

多个数的最小公倍数
与上题一样,依次求最小公倍数即可

#include 
using namespace std;
int gcd(int s1,int s2)
{return s2?gcd(s2,s1%s2):s1;
    }
int n;
long long a[20],c;
int main()
{   while(cin>>n)
    {  for(int i=0;i<n;i++)
           cin>>a[i];
       c=a[0]*a[1]/gcd(a[0],a[1]);
       for(int i=2;i<n;i++)
         c=c*a[i]/gcd(c,a[i]);
       printf("%lld\n",c);
      }

    return 0;
}

LCM&GCD
代码中有注解(我自己写的)

#include 
using namespace std;
long gcd(long s1,long s2)   
{return s2?gcd(s2,s1%s2):s1;
    } 
long s,x,y,t,sum;

int main()
{   while(scanf("%ld",&t)!=-1)
    {
      while(t--)
      {
       scanf("%ld %ld",&x,&y);
       s=x*y;       //假设a,b(a
       sum=0;         
       for(long i=x;i<=y;i+=x)  //因为x为a的约数,所以a只能是x的整数倍
         if(s%i==0 && gcd(i,s/i)==x)  //s为a的倍数,所以要保证s%i==0,同时要满足gcd(a,b)==x, 
              sum++;                   //因为gcd(i,s/i)==x成立时,(s/gcd(i,s/i))==y必成立,所以
       cout <<sum<< endl;              //不用判断了
      }
    }
    return 0;
}

这是李嘉文学长写的(百度直接搜索 nefu_ljw 即可进入学长的博客,感谢学长的代码)
假设gcd(a,b)=x,lcm(a,b)=y,则可得:gcdlcm=ab

即xy=ab,同除以x2,得y/x=(a/x)*(b/x)

令y1=y/x,a1=a/x,b1=b/x

则y1=a1*b1,且a1∈[1,y1]

这样化简之后,再遍历[1,sqrt(y1)](只需遍历到 根号y1 即可)找满足gcd(a1,b1)==1的情况,更新答案。

注意特判a1*a1=y的情况,答案+1;其他情况答案+2。

#include 
using namespace std;
int t,a,b,x,y,ans;
int main()
{
    ios::sync_with_stdio(false);
    cin>>t;
    while(t--)
    {
        cin>>x>>y;
        ans=0;
        if(y%x!=0){printf("0\n");continue;}//最大公倍数不是最小公约数的倍数,直接输出0
        y=y/x;//将y缩小到y1
        for(a=1;a*a<=y;a++)//在[1,y1]区间内暴力遍历所有a1的取值,每次+1
        {
            if(y%a==0)//满足y1=a1*b1,则b1=y1/a1,首先必须满足y%a==0
            {
                b=y/a;//直接得到b1的取值
                if(__gcd(a,b)==1)//gcd(a,b)==1则满足条件
                {
                    if(a*a==y)ans++;//特判a*a=y的情况,答案+1
                    else ans+=2;//其他情况答案+2
                }
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

人见人爱gcd
先来一些gcd的性质:
2019级ACM寒假训练第五天(Gcd&&Lcm,快速幂取模)_第1张图片
这一题用到了第三个和第五个性质,由lcm与gcd的转换公式可得2xy=2gcd(x,y)lcm(x,y),又(x+y)^2-2xy=x ^2+y ^2,所以求gcd(x,y)即可,因为
在这里插入图片描述在这里插入图片描述
所以在本题中gcd(x,y)=gcd(a,b),则x*y==gcd(a,b)*b

#include 
using namespace std;

long gcd( long a, long b)
{ return b?gcd(b,a%b):a;
    }
long a,b,s1,s2,t;

int main()
{   ios::sync_with_stdio(false);//取消输入输出同步流,一般在大数据cin或cout时使用,提高输入输出的速度
    while(cin>>t)
     {  while(t--)
        {  cin>>a>>b;
            s1=b*gcd(a,b);
            s2=a*a-2*s1;
            printf("%ld\n",s2);
           }
     }
     return 0;
}

高木同学的因子
找x和y的因子个数,因为x和y都是很大的数,如果单纯的暴力计算显然是会超时的。因为我们要计算两个数的公共因子个数,这两个数的公共因子显然是最大公因数的因子,而所有最大公因数的因子又都是这两个数的公共因子。所以我们把这个问题简化成为了求这两个数的最大公因数的因子的个数。

#include 
using namespace std;

typedef long long ll;
ll x,y;
int main()
{
    while(cin>>x>>y)
    {   int sum=0,s,i;
        s=__gcd(x,y);
        for(i=1;i*i<s;i++)
         {  if(s%i==0)  sum+=2;  //将s的因子分为两半,当i为因子时,s/i也为因子
         }
        if(i*i==s)
          sum++;
        printf("%d\n",sum);
    }
     return 0;
}

还有一种方法,即:(也是李嘉文学长的代码,感谢学长的代码,替学长宣传一下,百度直接搜索 nefu_ljw 即可进入学长的博客,(悄悄地告诉你,学长的代码比我的好多了))
2019级ACM寒假训练第五天(Gcd&&Lcm,快速幂取模)_第2张图片

#include 
using namespace std;
typedef long long ll;
ll x,y,ans=1;
int main()
{
    ios::sync_with_stdio(false);
    cin>>x>>y;
    ll k=__gcd(x,y);
    for(ll i=2;i*i<=k;i++)
    {
        ll c=0;
        while(k%i==0)
            k=k/i,c++;
        ans*=(c+1);
    }
    if(k>1)ans*=2;
    printf("%lld\n",ans);
    return 0;
}

快速幂取模
这题直接使用快速幂取模即可

#include 
using namespace std;
int  quickmod(long a,long b,long c)
  {  int ret=1;
     while(b)
     {  if(b&1)
          ret=ret*a%c;
        a=a*a%c;
        b/=2;
     }
     return ret;
    }
long A,B,C;
int main()
{   while(cin>>A>>B>>C)
    printf("%d\n",quickmod(A,B,C));
    return 0;
}

库特的数学题(显然不能使用数组)
刚开始以为这是一道递推题,但是推理一下(多写几项)才发现,a[n]=2*pow(3,n),求a[n]对1e9+7取模后的答案,所以这显然是一道快速幂取模的题目。(唉,数学差,一开始没推出来)

#include 
using namespace std;
long long mod(long long a,long long b,long long c)
  {  int ret=1;
     while(b)
     {  if(b&1)
          ret=ret*a%c;
        a=a*a%c;
        b/=2;//这一句也可以写成b>>=1;
     }
     return ret;
    }
    
long long n;
const long long m=1e9+7,x=3;

int main()
{   while(cin>>n)
    {  cout<<(mod(x,n,m)*2)%m<<endl;
    }
    return 0;
}

异或方程解的个数
先移项:a=x+(a^x),然后看二进制数的某一位,讨论即可发现规律:
a x+(a^x)
1 0+(1^0)==1
1 1+(1^1)==1
0 0+(0^0)==0
0 1+(0^1)==10
可以发现,第四种
当a=0,x=1时,会改变产生进位,改变了a的值,所以排除第四种情况
综合第三,四种情况,可以发现,如果a的某一位为0的话,那么x对应位只能为0。
再来看第一,第二种情况,我们发现,当a的某一位为1时,x的对应位可以为1,可以为0。
所以,我们只需求出a的二进制数中,有多少个1即可,答案即为2^n

#include 
using namespace std;

typedef long long ll;
ll n,s;
ll pow(int a,int b)
  { ll ans=1;
     for(int j=1;j<=b;j++)
        ans*=a;
     return ans;
   }

int main()
{   while(cin>>n)
    {   int sum=0;
        while(n)
         {  if(n%2==1)
             sum++;
            n/=2;
         }
         printf("%lld\n",pow(2,sum));
      }
    return 0;
}
#include 
using namespace std;
int pre[35],a,k,sum,i;
int main()
{
	pre[0]=1;
	for(i=1;i<=30;i++)
	pre[i]=2*pre[i-1];//先打表
	while(cin>>a)
    {
		sum=0;
        k=a;
        i=0;
		while(k)
       {  if((1<<i++)&a)
          sum++;
		   k/=2;
			}
		printf("%d\n",pre[sum]);
	}
	return 0;
}

你可能感兴趣的:(笔记)