寒假集训日志(三)——数论

  今天听得简直要崩溃。。。没听懂啥。。。

  主要内容:

  1.欧几里得(稍微懂了点)

  2.中国剩余定理( 稍微懂了点)

  3.博弈( 看智商的玩意儿)

(一)欧几里得算法(及其扩展算法)

  欧几里得定理就是gcd(辗转相除法)的原理(不懂,只会用)。

  扩展算法的运用大概就是用来解一个 ax + by = gcd( a, b )的不定方程。

  大致证明步骤:  将a 替换为b, 将b 替换为gcd(b, a%b),又gcd(a,b) = gcd( b, a%b),就可以化为一个等式巴拉巴拉的。然后算法实现的花就用递归:

  

//第一种,之后修改所得的 x , y 就是一组特解,通解的话直接根据系数在特解的基础上加减就好了
void exGcd ( ll a, ll b, ll &x , ll &y){
    if( b== 0) {
        x =1 ; y = 0;
        return ;
    }
    else{
    exGcd ( b, a% b, x, y);
    ll t = x;
    x = y;
    y = t - a/b* y;
    }
}
//第二种,简短,d最后得到的是 a, b的最大公约数 。 另外,注意这段代码 x, y需要交换位置的部分
void gcd( int a, int b, int &d, int &x, int &y){
    if(!b) { d = a ; x =1 ; y = 0 ;}
    else { gcd( b, a%b, d, y, x);
    y-= x*(a/b);
  }}

今天真正会做的也就3道。。。两道是这个算法的同类题,就放一道把。。。

A - 青蛙的约会

Time Limit:1000MS     Memory Limit:10000KB     64bit IO Format:%I64d & %I64u

Submit Status

Description

两只青蛙在网上相识了,它们聊得很开心,于是觉得很有必要见一面。它们很高兴地发现它们住在同一条纬度线上,于是它们约定各自朝西跳,直到碰面为止。可是 它们出发之前忘记了一件很重要的事情,既没有问清楚对方的特征,也没有约定见面的具体位置。不过青蛙们都是很乐观的,它们觉得只要一直朝着某个方向跳下 去,总能碰到对方的。但是除非这两只青蛙在同一时间跳到同一点上,不然是永远都不可能碰面的。为了帮助这两只乐观的青蛙,你被要求写一个程序来判断这两只 青蛙是否能够碰面,会在什么时候碰面。
我们把这两只青蛙分别叫做青蛙A和青蛙B,并且规定纬度线上东经0度处为原点,由东往西为正方向,单位长度1米,这样我们就得到了
一条首尾相接的数轴。设青蛙A的出发点坐标是x,青蛙B的出发点坐标是y。青蛙A一次能跳m米,青蛙B一次能跳n米,两只青蛙跳一次所花费的时间相同。纬
度线总长L米。现在要你求出它们跳了几次以后才会碰面。

Input

输入只包括一行5个整数x,y,m,n,L,其中x≠y < 2000000000,0 < m、n < 2000000000,0 < L < 2100000000。

Output

输出碰面所需要的跳跃次数,如果永远不可能碰面则输出一行"Impossible"

Sample Input

1 2 3 4 5

Sample Output

4我的代码:
//这个题目要注意一下long long#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
typedef long long ll;
using namespace std;

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

void exGcd ( ll a, ll b, ll &x , ll &y){
    if( b== 0) {
        x =1 ; y = 0;
        return ;
    }
    else{
    exGcd ( b, a% b, x, y);
    ll t = x;
    x = y;
    y = t - a/b* y;
    }
}

int main(){
    ll x, y, m, n, L, k, t;

    cin>>x>>y>>m>>n>>L;
    ll a = n - m;
    ll b = L;
    ll c = x - y;
    ll d =gcd ( a,b);
    if(   c % d !=0 ){
    cout<<"Impossible"<<endl;
    return 0;
    }
    a /=d;
    b /= d;
    c /= d;
    exGcd ( a, b , t, k );
    t = c* t%b;
    if( t < 0 ) t+=b;
    //printf("%I64d\n", t);
    cout<< t<<endl;
    return 0;
}

(二) 中国剩余定理:

  就是解决一个似乎是叫韩信点兵的问题。(以下转自http://yzmduncan.iteye.com/blog/1323599/)

  互质版的很好懂,就是直接一公式就出来了。

MOD M

  非互质版的比较麻烦,代码也有点乱,就是采取合并的方法,暂时没弄懂,需好好体会。

中国剩余定理

中国剩余定理是中国古代求解一次同余方程组的方法,是数论中的一个重要定理。

设m1,m2,m3,...,mk是两两互素的正整数,即gcd(mi,mj)=1,i!=j,i,j=1,2,3,...,k.

则同余方程组:

x = a1 (mod n1)

x = a2 (mod n2)

...

x = ak (mod nk)

模[n1,n2,...nk]有唯一解,即在[n1,n2,...,nk]的意义下,存在唯一的x,满足:

x = ai mod [n1,n2,...,nk], i=1,2,3,...,k。

解可以写为这种形式:

x = sigma(ai* mi*mi‘) mod(N)

      其中N=n1*n2*...*nk,mi=N/ni,mi‘为mi在模ni乘法下的逆元。

中国剩余定理非互质版

中国剩余定理求解同余方程要求模数两两互质,在非互质的时候其实也可以计算,这里采用的是合并方程的思想。下面是详细推导。

互质版:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    typedef __int64 int64;
    int64 a[15],b[15];  

    int64 Extend_Euclid(int64 a, int64 b, int64&x, int64& y)
    {
        if(b==0)
        {
            x=1,y=0;
            return a;
        }
        int64 d = Extend_Euclid(b,a%b,x,y);
        int64 t = x;
        x = y;
        y = t - a/b*y;
        return d;
    }
    //求解模线性方程组x=ai(mod ni)
    int64 China_Reminder(int len, int64* a, int64* n)
    {
        int i;
        int64 N = 1;
        int64 result = 0;
        for(i = 0; i < len; i++)
            N = N*n[i];
        for(i = 0; i < len; i++)
        {
            int64 m = N/n[i];
            int64 x,y;
            Extend_Euclid(m,n[i],x,y);
            x = (x%n[i]+n[i])%n[i];
            result = (result + m*a[i]*x%N)%N;
        }
        return result;
    }  

    int main()
    {
        int n;
        while(scanf("%d",&n)!=EOF)
        {
            for(int i = 0; i < n; i++)
                scanf("%I64d %I64d",&a[i],&b[i]);
            printf("%I64d\n",China_Reminder(n,b,a));
        }
        return 0;
    }  

非互质版:

    /**
    中国剩余定理(不互质)
    */
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    typedef __int64 int64;
    int64 Mod;  

    int64 gcd(int64 a, int64 b)
    {
        if(b==0)
            return a;
        return gcd(b,a%b);
    }  

    int64 Extend_Euclid(int64 a, int64 b, int64&x, int64& y)
    {
        if(b==0)
        {
            x=1,y=0;
            return a;
        }
        int64 d = Extend_Euclid(b,a%b,x,y);
        int64 t = x;
        x = y;
        y = t - a/b*y;
        return d;
    }  

    //a在模n乘法下的逆元,没有则返回-1
    int64 inv(int64 a, int64 n)
    {
        int64 x,y;
        int64 t = Extend_Euclid(a,n,x,y);
        if(t != 1)
            return -1;
        return (x%n+n)%n;
    }  

    //将两个方程合并为一个
    bool merge(int64 a1, int64 n1, int64 a2, int64 n2, int64& a3, int64& n3)
    {
        int64 d = gcd(n1,n2);
        int64 c = a2-a1;
        if(c%d)
            return false;
        c = (c%n2+n2)%n2;
        c /= d;
        n1 /= d;
        n2 /= d;
        c *= inv(n1,n2);
        c %= n2;
        c *= n1*d;
        c += a1;
        n3 = n1*n2*d;
        a3 = (c%n3+n3)%n3;
        return true;
    }  

    //求模线性方程组x=ai(mod ni),ni可以不互质
    int64 China_Reminder2(int len, int64* a, int64* n)
    {
        int64 a1=a[0],n1=n[0];
        int64 a2,n2;
        for(int i = 1; i < len; i++)
        {
            int64 aa,nn;
            a2 = a[i],n2=n[i];
            if(!merge(a1,n1,a2,n2,aa,nn))
                return -1;
            a1 = aa;
            n1 = nn;
        }
        Mod = n1;
        return (a1%n1+n1)%n1;
    }
    int64 a[1000],b[1000];
    int main()
    {
        int i;
        int k;
        while(scanf("%d",&k)!=EOF)
        {
            for(i = 0; i < k; i++)
                scanf("%I64d %I64d",&a[i],&b[i]);
            printf("%I64d\n",China_Reminder2(k,b,a));
        }
        return 0;
    }  

题目就不给出了,基本一眼就可以看出来,也很难有什么改变。

(三)博弈论

  此类题变幻无穷。。。及其考智商,只是任何时候都别忘了dp。。

  另外,打表的方法一定要学会。

时间: 2024-07-28 13:35:03

寒假集训日志(三)——数论的相关文章

寒假集训日志(二)——最小生成树,拓扑排序,欧拉回路,连通路

今天学的内容挺多的. (一)首先说最小生成树,两种算法: 1.Kruskal算法( 将边排序,然后再选,关键在于检查是否连通,使用并查集) 2.Prim算法(使用点集,有点类似与最短路的算法) 第一题是并查集算法的使用: A - The Suspects Time Limit:1000MS     Memory Limit:20000KB     64bit IO Format:%I64d & %I64u Submit Status Description 严重急性呼吸系统综合症( SARS),

寒假集训日志(五)——期中测验

10道题目,A了4道,5道会做,5道不会,果然渣渣... 这次测验感觉无限段错误..一个是初始化的问题,还一个建树的过程出错,但还不知道错在哪里.先附上几道没A的题, 以后慢慢解决. B - 拓扑 Time Limit:2000MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I64u Submit Status Practice CodeForces 510C Description Fox Ciel is going to p

寒假集训日志(一)——图,最短路问题

今天主要学习了图的有关内容,以及DFS,BFS,最短路问题的大致讲解,做了4道习题,完成了今日任务. 最短路的三种算法: 1.Dijkstra算法(使用连接矩阵,打起来简单,但是复杂度高) 2.Bellman Ford算法(松弛操作, 使用较少) 3.SFPA算法(第一种算法的优化,使用最多) 另外,求两个点之间的最短路:Floyd算法 今天做的4道题: A - 最短路 Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:

寒假集训日志(六)——DP

(一)数位DP 1057. Amount of Degrees Time limit: 1.0 secondMemory limit: 64 MB Create a code to determine the amount of integers, lying in the set [X;Y] and being a sum of exactly K different integer degrees of B. Example. Let X=15, Y=20, K=2, B=2. By thi

Contest1692 - 2019寒假集训第三十一场 UPC 11075 Problem D 小P的国际象棋

非常简单的单点修改+区间加+区间查询.我用的是最近刚学的区间修改版本树状数组.  直接维护即可,注意修改后的单点值已经不是a[i],或者b[i],要通过区间查询求单点.不然是错的. 区间修改版本树状数组: #include<iostream> #include<string.h> #include<stdio.h> #include<algorithm> #define LL long long using namespace std; LL c_p[400

浅谈SQL Server中的事务日志(三)----在简单恢复模式下日志的角色

浅谈SQL Server中的事务日志(三)----在简单恢复模式下日志的角色 本篇文章是系列文章中的第三篇,前两篇的地址如下: 浅谈SQL Server中的事务日志(一)----事务日志的物理和逻辑构架 浅谈SQL Server中的事务日志(二)----事务日志在修改数据时的角色 简介 在简单恢复模式下,日志文件的作用仅仅是保证了SQL Server事务的ACID属性.并不承担具体的恢复数据的角色.正如”简单”这个词的字面意思一样,数据的备份和恢复仅仅是依赖于手动备份和恢复.在开始文章之前,首先

MySQL binlog日志三种模式选择及配置

在讲解binlog日志三种模式前,先了解一下解析binlog日志的命令工mysqlbinlog.mysqlbinlog工具的作用是解析mysql的二进制binlog日志内容,把二进制日志解析成可以在MySQL数据库里执行的SQL语句.binlog日志原始数据是以二进制形式存在的,需要使用mysqlbinlog工具转换成SQL语句形式.mysql的binlog日志作用是用来记录mysql内部增删改等对mysql数据库有更新内容的记录(对数据库进行改动的操作),对数据库查询的语句如show,sele

CSU-ACM寒假集训选拔-入门题

CSU-ACM寒假集训选拔-入门题 仅选择部分有价值的题 J(2165): 时间旅行 Description 假设 Bobo 位于时间轴(数轴)上 t0 点,他要使用时间机器回到区间 (0,?h] 中. 当 Bobo 位于时间轴上 t 点,同时时间机器有 c 单位燃料时,他可以选择一个满足 \(\lceil\frac{x}{h}\rceil\leq c\) 的非负整数 x, 那么时间机器会在 [0,?x]中随机整数 y,使 Bobo 回到 (t???y) 点,同时消耗 y 单位燃料. (其中 ?

题解报告(CDUT暑期集训——第三场)

题解报告(CDUT暑期集训--第三场) A - Problem A. Ascending Rating HDU - 6319 思路:单调队列板子题?(但是弱的一批的我还是不会用(有空补上 用的滑动窗口算法 按着题解的从后往前做(ps:菜是原罪 AC代码 #include<stdio.h> #include<iostream> #include<math.h> #include<algorithm> #include<string.h> #incl