博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
寒假集训日志(三)——数论
阅读量:6680 次
发布时间:2019-06-25

本文共 6144 字,大约阅读时间需要 20 分钟。

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

  主要内容:

  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

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
#include
#include
#include
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"<

(二) 中国剩余定理:

  就是解决一个似乎是叫韩信点兵的问题。(以下转自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 
#include
#include
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 
#include
#include
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。。

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

   直接加上两句话就行了:

  freopen("input.txt", "r", stdin);   //将文件中的数据输入

  freopen("output.txt", "w", stdout);  //将程序中的输出输出到文件中

转载于:https://www.cnblogs.com/topW2W/p/5156283.html

你可能感兴趣的文章
linux常用命令 2
查看>>
jquery中prop和attr的区别
查看>>
2016-2017 ACM-ICPC Pacific Northwest Regional Contest (Div. 1) Problem K Tournament Wins
查看>>
台州学院we are without brain 训练 计算几何
查看>>
Webpack 代码分离
查看>>
ssh下:系统初始化实现ServletContextListener接口时,获取spring中数据层对象无效的问题...
查看>>
extundelete
查看>>
powerviot install in sharepoint 2013
查看>>
javascript在我的工作的用法
查看>>
《告诉他们,我已乘白鹤去了》观后感——用生命换取信仰
查看>>
诡秘的“端口安全”功能
查看>>
市场活动课件:SQL Server 索引优化
查看>>
Linux程序包管理rpm命令的使用解析
查看>>
什么是证书颁发机构(CA)
查看>>
php-fpm定义成集群资源时报错解决方法
查看>>
FORM开发相关技术(二)
查看>>
实战DeviceIoControl 之一:通过API访问设备驱动程序
查看>>
MFC消息循环
查看>>
配置Spring数据源
查看>>
Jquery元素追加和删除
查看>>