4.14~4.20数论①

版权声明: https://blog.csdn.net/zjh_2017/article/details/80024139

gcd和lcm

一行GCD

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

二进制算法

inline int GCD(int x,int y)
{
    int i,j;
    if(!x)return y;
    if(!y)return x;
    for(int i=0;0==(x&1);++i)x>>=1;
    //0==(x&1)用来判断x二进制下最右边一位是否为0
    for(int j=0;0==(y&1);++j)y>>=1;
    if(j<i)i=j;//i表示二进制下右数连续的0的个数
    while(1)
    {
        if(x<y)x^=y,y^=x,x^=y;
        if(0==(x-=y))return y<<i;//y要乘原来除掉的2
        while(0==(x&1))x>>=1;
    }
}

除法表达式

我们可以发现,x[2]这个数总会在分母里出现
其他x都可以在分子里出现
= x [ 1 ] x [ 3 ] x [ k ] x [ 2 ]
然后进行约分即可
如果x[2]约到最后不为1,说明不可以

#include<bits/stdc++.h>
using namespace std;
string s;
long long temp,a[100010],s1=1,s2,g;
long long Gcd(long long x,long long y)
{
    return (y==0)?x:Gcd(y,x%y);
}
int main()
{
    getline(cin,s);
    for (int i=0;i<s.size();++i)
    {
        temp++;
        while (s[i]!='/'&&i<s.size())
        {
            a[temp]=a[temp]*10+s[i]-'0';
            i++;
        }
    }
    s2=a[2];
    for (int i=1;i<=temp;++i)
    {
        if (i==2) continue;
        g=Gcd(a[i],a[2]);
        s1*=a[i]/g;
        s2/=g;
        if (s2==1)
        {
            printf("YES\n");
            return 0;
        }
    }
    printf("NO\n");
    return 0;
}

同余和扩欧

快速幂

long long qpow(long long x,long long a){
    long long times=1,base=x,ans=1;
    while(times<=a){
        if(times&a){
            ans*=base;
            ans%=mod;
        }
        times<<=1;
        base*=base;
        base%=mod;
    }
    return ans;
}

快速乘

typedef long long ll; 
ll mul(ll x,ll y)
{
return ((x*y-(ll)(((long double)x*y+0.5)/mod)*mod)%mod+mod)%mod;
}

扩欧

long long a,b; 
struct  Triple {
     long long d,x,y;
}; 
Triple exgcd(long long a,long long b) {
    if(b==0) { 
        return (Triple){a,1,0}; 
    } 
    Triple t=exgcd(b,a%b); 
    return (Triple){t.d,t.y,t.x-a/b*t.y}; 
}

contest

通过推结论,我发现答案就是 2 n 2
你可以这么想:对于每一个位置上的数,假设已保证它左边的序列和右边的序列都具有单调性,那么它只有两种可能——一种是根据左边的序列进行单调,另一种是根据右边的序列进行单调,这就有了 2 n 种可能。但在序列的一头一尾上,各只有一种可能,所以要 2

#include<bits/stdc++.h>
using namespace std;
long long n,p,ans;
long long mul(long long x,long long y)
{
    return ((x*y-(long long)(((long double)x*y+0.5)/p)*p)%p+p)%p;
}
long long qpow(long long x,long long a)
{
    long long times=1,base=x,ans=1;
    while (times<=a)
    {
        if (times&a)
        {
            ans=mul(ans,base);
            ans%=p;
        }
        times<<=1;
        base=mul(base,base);
        base%=p;
    }
    return ans;
}
int main()
{
    while (scanf("%lld %lld",&n,&p)!=EOF)
    {
        if (n==1) ans=1;
        else ans=(qpow(2,n)-2+p)%p;
        printf("%lld\n",ans);
    }
    return 0;
}

青蛙的约会

设走了t天
x < y ,则有x+mt=y+nt+kL
我们需要求解t的正整数解
直接扩欧

#include<bits/stdc++.h>
using namespace std;
long long x,y,m,n,l;
struct Triple
{
    long long d,x,y;
};
inline int read()
{
    int num=0,flag=1;
    char c=getchar();
    for (;c<'0'||c>'9';c=getchar())
    if (c=='-') flag=-1;
    for (;c>='0'&&c<='9';c=getchar())
    num=(num<<3)+(num<<1)+c-48;
    return num*flag;
}
Triple exgcd(long long a,long long b)
{
    if (b==0)
    { 
        return (Triple){a,1,0};
    }
    Triple t=exgcd(b,a%b);
    return (Triple){t.d,t.y,t.x-a/b*t.y}; 
}
int main()
{
    x=read();
    y=read();
    m=read();
    n=read();
    l=read();
    if (x>y)
    {
        swap(x,y);
        swap(m,n);
    }
    Triple t=exgcd(n-m,l);
    if ((x-y)%t.d!=0)
    {
        printf("Impossible\n");
        return 0;
    }
    t.x=t.x*(x-y)/t.d;
    t.x=(t.x%l+l)%l;
    printf("%lld\n",t.x);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/zjh_2017/article/details/80024139