1. 程式人生 > >4.14~4.20數論①

4.14~4.20數論①

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;
}