大一寒假集训(5)----GCD与快速幂取模

大一寒假集训(5)----GCD与快速幂取模 nefu

Gcd 求最大公约数(三种)

1.辗转相除法 欧几里得算法
(1)非递归模板
通常不使用,为了方便理解递归模板使用

int gcd (int a,int b)
{
    int r=a%b;
    while (r)
    {
        a=b;
        b=r;
        r=a%b;
    }
    return b;
}

(2) 递归模板
经常使用

int gcd (int a,int b)
{
    return b?gcd(b,a%b):a;
}

其中? :
相当于

if (b!=0)
   return gcd(b,a%b);
else return a;

2.辗转相减法 更相减损术
易超时,不常用
3.素因子法

Lcm 最小公倍数

在这里插入图片描述
先除法后乘法,防溢出

快速幂取模

基本性质
(a+b)%m=(a%m+b%m)%m
(ab)%m=(a%mb%m)%m
(1)非递归模板

ll quickmod (ll a,ll b,ll c)
{
    int ret=1;
    while (b)
    {
        if (b&1)//奇数最后一位为1,b%2==1也可用,速度差不多
            ret=ret*a%c;
        a=a*a%c;
        b/=2;//向下取整
    }
    return ret;
}

(2)递归模板

1.最大公约数和最小公倍数 nefu 1077

本题几乎完全引用模板

#include <iostream>
#include <bits/stdc++.h>

using namespace std;
int gcd (int a,int b)
{
    return b?gcd (b,a%b):a;
}
int main()
{
    int a,b;
    int g,l;
    while (cin>>a>>b)
    {
        g=gcd(a,b);
        l=(a*b)/g;
        printf("%d %d\n",g,l);
    }
    return 0;
}
2.又见GCD nefu 992

(1)(TLE)

#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int gcd (int a,int b)
{
    return b?gcd(b,a%b):a;
}
int main()
{
    int a,b,c;
    int r;
    while (cin>>a>>b)
    {
        int minn=1000000;
        for (int i=a*b;i>b;i--)
        {
            r=gcd(a,i);
            if (r==b&&minn>r)
            {
                minn=i;
            }
        }
        cout<<minn<<endl;
    }
    return 0;
}

(2)AC

#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int gcd (int a,int b)
{
    return b?gcd(b,a%b):a;
}
int main()
{
    int a,b;
    int r;
    while (cin>>a>>b)
    {
        int minn=1000000;
        for (int i=b+1;;i++)
        {
            r=gcd(i,a);
            if (r==b)
            {
                printf("%d\n",i);
                break;
            }
        }
    }
    return 0;
}
3.多个数的最大公约数 nefu 764
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int gcd (int a,int b)
{
    return b?gcd(b,a%b):a;
}
int main()
{
    int n;
    long long a[12];
    while (cin>>n)
    {
        for (int i=1;i<=n;i++)
            cin>>a[i];
        for (int i=1;i<n;i++)
        {
            a[i+1]=gcd(a[i],a[i+1]);
        }
        printf("%lld\n",a[n]);
    }
    return 0;
}

4.多个数的最小公倍数 nefu 765
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int gcd (int a,int b)
{
    return b?gcd(b,a%b):a;
}
int main()
{
    int n;
    long long a[12];
    while (cin>>n)
    {
        for (int i=1;i<=n;i++)
            cin>>a[i];
        for (int i=1;i<n;i++)
        {
            a[i+1]=(a[i+1]*a[i])/gcd(a[i],a[i+1]);
        }
        printf("%lld\n",a[n]);
    }
    return 0;
}

5.快速幂取模 nefu 601

套模板

#include <iostream>
#include <bits/stdc++.h>
using namespace std;
long long quickmod (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=b/2;
    }
    return ret;

}
int main()
{
    long long a,b,c;
    long long re;
    while (cin>>a>>b>>c)
    {
        re=quickmod(a,b,c);
        printf("%lld\n",re);
    }
    return 0;
}

6.人见人爱gcd nefu 1221

暴力会TLE
直接运用数学公式做

#include <iostream>
#include <bits/stdc++.h>
using namespace std;
long long gcd(long long a,long long b)
{
    return b?gcd(b,a%b):a;
}
int main()
{
    ios::sync_with_stdio(false);
    int t;
    while (cin>>t)
    {
        for (int r=0; r<t; r++)
        {
            long long a,b;
            long long x,y;
            long long re;
            cin>>a>>b;
            //y=a-x;
           /* for (int i=1;;i++)
            {
                re=i/gcd(i,a-i)*(a-i);
                if (b==re)
                {
                    x=i;
                    y=a-i;
                    break;
                }
            }*///用暴力不会AC


            printf("%lld\n",a*a-2*b*gcd(a,b));
        }

    }

    return 0;
}

7.LCM&GCD nefu 1411

(1)今天第无数次TLE:)
我疯了 :)

#include <iostream>
#include <bits/stdc++.h>

using namespace std;
int gcd (int a,int b)
{
    return b?gcd(b,a%b):a;
}

int main()
{
    int t;
    while(cin>>t)
    {
        ios::sync_with_stdio(false);
        while (t--)
        {
            int x,y;//1<=x<=y<=1e6
            //int a,b;
            int temp;
            int ans=0;
            cin>>x>>y;
            //y=y/2;
            for (int i=1;i<=y/2;i++)
            {
                for (int j=y;j>=y/2;j--)
                {
                    temp=gcd(i,j);
                    if (temp==x&&y==i/x*j)
                        ans++;
                }
            }
            cout<<ans*2<<endl;
        }
    }
    return 0;
}


(2)

8.库特的数学题 nefu 1666

1.将a[3],a[4]都算出来就可以发现规律,可分解,并利用快速幂取模法计算。但因a[n]通式多出一个2,所以可用 (ab)%m=(a%mb%m)%m 公式进行分解
2.数据过大拒绝暴力

#include <iostream>
#include <bits/stdc++.h>
using namespace std;
long long quickmod (long long a,long long b,long long c)//a=3,b=n,c=modx<先求3^n取模再利用公式 (a*b)%m=(a%m*b%m)%m
{
    int ret=1;
    while (b)
    {
        if (b&1)//奇数最后一位为1,b%2==1也可用,速度差不多
            ret=ret*a%c;
        a=a*a%c;
        b/=2;//向下取整
    }
    return ret;
}//套用快速幂取模模板

int main()
{
    long long n;//注意输入的n的大小,第一次因为将其设成int 就wa了一次 :)
    int mod=1000000007;
    long long ans1,ans2;
    //int a[100000];
    while (cin>>n)
    {
         ios::sync_with_stdio(false);
         //a[n]=2*3^n;
        /*for (int i=1;i<=1000000007;i++)
            a[i]=2*a[i-1]+3*a[i-2];//打个p表*///暴力打表太蠢了
        ans1=quickmod(3,n,mod);
        ans2=(2%mod*ans1)%mod;
        cout<<ans2<<endl;

    }
    return 0;
}

9.异或方程解的个数 nefu 1834

在这里插入图片描述

#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int main()
{
    int n;
    int a[1000];
    int r=0;
    while (cin>>n)
    {
        int sum=0;
        int ans=1;
        while (n!=0)
        {
            a[r]=n%2;
            n=n/2;
            r++;
        }//转化为二进制
        for (;r>0;r--)
            if(a[r-1]==1)
            sum++;
        for (int i=0;i<sum;i++)
            ans*=2;
        cout<<ans<<endl;
    }
    return 0;
}

10.LCM&GCD nefu 1411
#include <iostream>

using namespace std;
int gcd(int a,int b)
{
    return b ?gcd(b,a%b):a;
}

int main()
{
    long long x,y,t,k;
    long long i,j,sum;
    ios::sync_with_stdio(false);//提高输入输出效率
    while(cin>>t)
    {
        sum=0;
        while(t--)
        {
            
            sum=0;
            cin>>x>>y;
              for(i=x;i<=y;i++)
            {
                 j=x*y/i;
                 if(x*y%i==0&&j>=x&&j<=y&&gcd(i,j)==x)//注意此处的限制条件,易丢弃j>=x和j<=y
                 sum++;
            }
            cout<<sum<<endl;
        }
    }


    return 0;
}
11.高木同学的因子 nefu 1699

(1)处我一开始写的是下面的代码,结果开始了TLE之旅。。。。
本题解用暴力,但应只用一层for 循环,否则易TLE。

for (i=1;i<n;i++)
    {
        if (n%i==0)
            ans+=1;
    }
#include <bits/stdc++.h>

using namespace std;
int main()
{
    ios::sync_with_stdio(false);//提高输入输出效率
    long long x,y;
    long long n;
    int i;
    cin>>x>>y;
    int ans=0;
    n=__gcd(x,y);//c++中可直接使用  ————gcd(x,y)
    for (i=1;i*i<n;i++)
    {
        if (n%i==0)
            ans+=2;//(1)
    }
    if (i*i==n) ans++;
    cout<<ans<<endl;
    return 0;
}


终于全做完了,今天可怕的不是WA而是TLE,今天是TLE的一天。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值