《数论及应用》第1章 数的整除性问题

1.整除问题 。


http://acm.nefu.edu.cn/JudgeOnline/problem/115.jsp

水题,斐波那契数列是有循环节的。

罗列斐波那契数列前几项如1 1 2 3 5 8 13 21 34 55 89 144 233 ... 发现能被3整除的刚好是4的循环,能被4整除的刚好是6的循环,猜想存在这种关系,可以用数学归纳法证明: 

f ( n )  =  f ( n - 1 ) + f ( n - 2 )

   = 2 * f ( n -1 ) + f ( n - 3 )

   = 3 * f ( n - 3 ) + 2 * f  ( n - 4 )  //    可以证明被3整除   循环节是4

   = 5 * f ( n -4 )  + 3 * f ( n - 5 )

   = 8 * f ( n - 5 ) + 5 * f ( n - 6 )   //    可以证明被4整除  循环节是6

题目也求能否被 12 整除 , 而3 和4 的最小公倍数就是 12 所以它的循环节是 4 和 6 的最小公倍数也就是 12 。


#include <stdio.h>
int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        if(n%12==0)
            printf("YES\n");
        else
        {
            if(n%4==0)
                printf("3\n");
            else if(n%6==0)
                printf("4\n");
            else
                printf("NO\n");
        }
    }
    return 0;
}




杭电上一道类似的题  水啊

http://acm.hdu.edu.cn/showproblem.php?pid=1021

思路是一样的....水啊

#include <stdio.h>
int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        if(n%4==2)
        printf("yes\n");
        else
        printf("no\n");
    }
    return 0;
}



2. gcd 和 lcm

a * b = gcd ( a,b ) * lcm ( a,b ) 

gcd ( ma,mb ) = m * gcd ( a,b ) (那个啥书上的是错的,这个才是对的)

辗转相除法:   a = q * b + r    gcd ( a,b ) = gcd ( b,r ) 



http://acm.nefu.edu.cn/JudgeOnline/problem/116.jsp

水题....哦..这个oj蛮坑人的,_int64做的就PE了,只能用long long

#include <stdio.h>
long long  gcd(int x,int y)
{
    if(y==0) return  x;
    return gcd(y,x%y);
}
int main()
{
    int a,b;
    while(scanf("%d%d",&a,&b)!=EOF)
    {
        printf("%lld\n",(long long)a*b/gcd(a,b));
    }
    return 0;
}




3.扩展欧几里得

设a和b不全为0,则存在整数x和y使得 gcd ( a,b ) = a * x +b * y

推论: a , b 互素 当且仅当 a * x + b * y =1


http://poj.org/problem?id=1061

丫的,第一次做扩展欧几里得,模板妹的坑爹,尤其是这本书的这一块

线性同余,这是一个好东西的嘛

关于这个题,首先还是列方程:(中间可以进行优化,先求gcd(a,b),然后以方程两边除它可以简化)

设青蛙跳了 t 步 他们相遇的充要条件就是 (x+mt)-(y+nt)=pl 即 (n-m)* t + l * p = x-y

可以直接看成 a*x+b*y=gcd(a,b)

关于模板函数中带 &的变量当然是之后要返回那个值,所以最后得到的x,y便是一组通解

数论概论书上讲了个线性方程定理(第三版 p25): g = gcd ( a , b ),方程 ax + by = g 存在一个解(x , y )由函数返回得到,则方程的每一个解都可以表示成 (x+k*b/g,y-k*a/g )(k为任意整数)    那么剩下的问题就好解决了 


#include <stdio.h>
long long gcd(long long a,long long b)
{
    if(b==0) return a;
    return gcd(b,a%b);
}
long long exgcd(long long a,long long b,long long &x,long long &y)
{
    long long ans,t;
    if(b==0)
    {
        x=1;y=0;return a;
    }
    else
    {
        ans=exgcd(b,a%b,x,y);
        t=x;x=y;y=t-(a/b)*y;
    }
    return ans;
}
int main()
{
    long long x,y,n,m,l;
    long long a,b,d,k,s,t,r;
    scanf("%lld%lld%lld%lld%lld",&x,&y,&m,&n,&l);
    //方程:(n-m)*s+l*k=d
    a=n-m;
    b=l;   // a*s+b*k=d;
    d=x-y;
    r=gcd(a,b);
    if(d%r!=0)
    {
        printf("Impossible\n");
        return 0;
    }
    a/=r;
    b/=r;
    d/=r;
    exgcd(a,b,s,k);
    s*=d;// 方程的通解:s=s1+t*b/d;k=k1+t*a/d;
    //由于求的是最小解,则令s=0;
    k*=d;  //乘以d后分别是 s1=-t*b 和 k1=-t*a
    t=s/b;//通解的系数的相反数嘛
    s=s-t*b;
    if(s<0)
        s+=b;
    printf("%lld\n",s);
    return 0;
}



说实话,扩展欧几里得之后的处理还是有那么一点不懂,估计多看几个题就是了
原书上的鬼代码还是敲一遍为好,后面的处理它直接用一个式子就搞定了
若有解,M=gcd(n-m,l),X=X(x-y)/M
t = ((X%(l/M)+l/M)%(l/M))就是最后的解

#include <cstdlib>
#include <iostream>
typedef long long int64;
using namespace std;
int64 exgcd(int64 m,int64 &x,int64 n,int64 &y)
{
    //尼玛坑爹的欧几里得,还是递归的简单
    int64 x1,y1,x0,y0;
    x0=1;y0=0;
    x1=0;y1=1;
    int64 r=(m%n+n)%n;
    int64 q=(m-r)/n;
    x=0;y=1;
    while(r)
    {
        x=x0-q*x1;y=y0-q*y1;x0=x1;y0=y1;
        x1=x;y1=y;
        m=n;n=r;r=m%n;
        q=(m-r)/n;
    }
    return n;
}
int main()
{
    int yy;
    int64 r,t,x,y,m,n,l,ar,br,cr;
    cin>>x>>y>>m>>n>>l;
    int64 M=exgcd(n-m,ar,l,br);
    if((x-y)%M||m==n)
    cout<<"Impossible"<<endl;
    else
    {
        int64 s=l/M;
        ar=ar*((x-y)/M);
        ar=(ar%s+s)%s;
        cout<<ar<<endl;
    }
    return 0;
}



http://acm.nefu.edu.cn/JudgeOnline/problem/84.jsp
算是一样的题吧
同样先写出方程 s * d  -  t  * n = m


#include <stdio.h>
long long gcd(long long a,long long b)
{
    if(b==0) return a;
    return gcd(b,a%b);
}
long long exgcd(long long a,long long b,long long &x,long long &y)
{
    if(b==1) //貌似是说走一圈的意思
    {
        x=1;
        y=1-a;
    }
    else
    {
        long long x1,y1;
        exgcd(b,a%b,x1,y1);
        x=y1;
        y=x1-x*(a/b);
    }
}
int main()
{
    int tc;
    long long n,d,x,y,g,s,t,res;
    scanf("%d",&tc);
    while(tc--)
    {
        scanf("%lld%lld%lld%lld",&n,&d,&x,&y);
        x=(y-x+n)%n;
        g=gcd(d,n);
        if(x%g)
        {
            printf("Impossible\n");
            continue;
        }
        n/=g;
        d/=g;
        exgcd(d,n,s,t);
        if(s<0)
        s+=n;
        res=(s*x/g)%n;
        printf("%lld\n",res);
    }
    return 0;
}			

至于课后习题,简单的就不累述了,难的我也解决不了,时间紧迫,以后再看吧:
设a>b,gcd(a,b)=1,证明 (a^m-b^m,a^n-b^n)=a^(m,n) - b^(m,n)  (主要思路估计还是辗转相除变形)












  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值