【lydsy1407】拓展欧几里得求解不定方程+同余方程

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1407

题意:

有n个野人,野人各自住在第c[i]个山洞中(山洞成环状),每年向前走p[i]个山洞,到这个山洞住下来。

每个野人的寿命为l[i],问至少需要多少个山洞,才能让野人在有生之年永远不住在同一个山洞。

题解:

原本不会拓展欧几里得和同余方程,在这里尽量详细地写一下由这题学到的东西。

我原本是从网上看各类题解然后打的,因为不理解和某些题解上的错误,导致调了很久。

下面写我的题解,如有错误,敬请指出。

设山洞的数量为m。

首先,对于n=2时,若相遇,则得同余方程 c[i]+x*p[i] = c[j]+x*p[j] (mod m)

移项,得:(p[i]-p[j])*x=c[j]-c[i] (mod m)

即:(p[i]-p[j])*x + m*y = c[j]-c[i]

则由于p[i]-p[j]、m、c[j]-c[i]已知,该方程相当于 a*x+b*y=c,可用拓展欧几里得求解。

若该方程无解,或x小于l[i]且x小于l[j](注意是并且的关系,因为一个死了一个活着也是不能相遇的),则不会相遇。

所以,由于n<=15,可以从max(c[i])开始枚举m(因为开始时野人都不在同一个山洞,max(c[i])一定大于等于n),两两匹配,若都不能相遇,则当前的m值为最小整数解。

相关: 用拓展欧几里德算法求不定方程 a*x + b*y = c:

推荐一篇很好的博文:http://www.cnblogs.com/Rinyo/archive/2012/11/25/2787419.html

如果c不是gcd(a,b)的倍数,则该方程无解。

证明:

设g=gcd(a,b),则a=a‘g,b=b‘g

ax+by=c可化为g(a‘x+b‘y)=c

由于g、(a‘x+b‘y)、c都是整数,所以c必然是g的倍数。

拓展欧几里得:

int exgcd(int a,int b)
{
	if (b == 0) { x=1,y=0; return a; }
	int t = exgcd (b,a%b,x,y);
	int x0 = x , y0 = y;
	x = y0; y = x0-(a/b)*y0;
	return t;
}

证明:

ax + by = gcd(a,b)

bx‘+(a%b)y‘=gcd(b,a%b)

因为gcd(a,b) = gcd(b,a%b)

所以ax+by = bx‘+(a%b)y‘

代入a%b =  a - ⌊a/b⌋*b (⌊⌋是向下取整符号)

ax + by = bx‘ + (a - ⌊a/b⌋*b)y‘

ax + by = ay‘ + b(x‘-⌊a/b⌋y‘)

所以: x = y‘  y = x‘-⌊a/b⌋*y‘

回溯即可得出答案。

此处求出的x和y是一组可行解,可以利用通式

x = x‘ + k*b

y = y‘ + k*b

求出最小整数解。

注意:ax + by = c 求的是c是gcd(a,b)的倍数时的解。

方法一:

方程两边同时除以g

a‘=a/g   b‘=b/g   c‘=c/g

得a‘x+b‘y=c‘

用拓展欧几里德算法求解a‘x‘+b‘y‘=1

则 x = x‘*c‘  y = y‘*c‘

这时,在用通式求最小整数解时加减的应是b‘

方法二:

我们可以直接求出ax’ + by’ =1

则 x = x‘*c/g   y = y‘ * c/g

这时应注意,在求通式求最小整数解加减的仍应是b/g。(注意!)

代码如下:

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<iostream>
 5 using namespace std;
 6
 7 const int N=20,M=1000010;
 8 int n;
 9 int cc[N],p[N],l[N];
10
11 int maxx(int x,int y) {return x>y ? x:y;}
12 int minn(int x,int y) {return x<y ? x:y;}
13 int myabs(int x) {return x>0 ? x:-x;}
14
15 int gcd(int a,int b)
16 {
17     if(b==0) return a;
18     return gcd(b,a%b);
19 }
20
21 void exgcd(int a,int b,int &x,int &y)
22 {
23     if(b==0) {x=1,y=0;return ;}
24     exgcd(b,a%b,x,y);
25     int x0=x,y0=y;
26     x=y0;y=x0-(a/b)*y0;
27     return ;
28 }
29
30 bool check(int m)
31 {
32     for(int i=1;i<=n-1;i++)
33         for(int j=i+1;j<=n;j++)
34         {
35             int a=p[i]-p[j];
36             int b=m;
37             int c=cc[j]-cc[i];
38
39             int g=gcd(a,b);
40             if(c%g) continue;
41             a/=g;b/=g;c/=g;//b在此处可能变为负
42             int x,y;
43             exgcd(a,b,x,y);
44             x=x*c;y=y*c;
45             while(x>0) x-=myabs(b);
46             while(x<=0) x+=myabs(b);
47             if(x<=minn(l[i],l[j])) return 0;//
48         }
49     return 1;
50 }
51
52 int main()
53 {
54     scanf("%d",&n);
55     int mx=n;
56     for(int i=1;i<=n;i++)
57     {
58         scanf("%d%d%d",&cc[i],&p[i],&l[i]);
59         mx=maxx(mx,cc[i]);
60     }
61     for(int i=mx;i<=M;i++)
62     {
63         if(check(i)) {printf("%d\n",i);break;}
64     }
65     return 0;
66 }

时间: 2024-10-09 21:46:51

【lydsy1407】拓展欧几里得求解不定方程+同余方程的相关文章

数论之拓展欧几里得求解不定方程和同余方程组(一)

今天接到scy的压缩包,开始做数论专题.那今天就总结一下拓展欧几里得求解不定方程和同余方程组. 首先我们复习一下欧几里得算法: 1 int gcd(int a,int b){ 2 if(b==0) return a; 3 return gcd(b,a%b);4 } 拓展欧几里得算法: 推导过程: 给出A和B,求它们的最大公约数,并且求出x和y,满足Ax+By=gcd(A,B). 当A=0时,x=0,y=1; 当A>0时, 因为exgcd(A,B,x,y)表示Ax+By=gcd(A,B) 而且ex

uva 1426 - Discrete Square Roots(拓展欧几里得)

题目链接:uva 1426 - Discrete Square Roots 题目大意:给出X,N,R,求出所有满足的r,使得r2≡x%N,并且R是一个其中的解. 解题思路: R2?r2=k?N (R?r)(R+r)=k?N => aA=(R+r),bB=(R?r),A,B为N的因子 所以枚举A,B,就有r=R?aA=bB?R aA+bB=2?R 拓展欧几里得求解,将所有满足的解放入set中自动去重. #include <cstdio> #include <cstring> #

HDU-3579-Hello Kiki (利用拓展欧几里得求同余方程组)

设 ans 为满足前 n - 1个同余方程的解,lcm是前n - 1个同余方程模的最小公倍数,求前n个同余方程组的解的过程如下: ①设lcm * x + ans为前n个同余方程组的解,lcm * x + ans一定能满足前n - 1个同余方程: ②第 n 个同余方程可以转化为a[n] * y + b; 合并①②得:lcm * x + ans = a[n] * y + b; => lcm * x - a[n] * y = b - ans(可以用拓展欧几里得求解x和y) 但是拓展欧几里得要求取余的数

ACM数论-欧几里得与拓展欧几里得

ACM数论--欧几里得与拓展欧几里得 欧几里得算法: 欧几里德算法又称辗转相除法,用于计算两个整数a,b的最大公约数. 基本算法:设a=qb+r,其中a,b,q,r都是整数,则gcd(a,b)=gcd(b,r),即gcd(a,b)=gcd(b,a%b). int gcd(int a,int b) { return b ? gcd(b,a%b) : a; } 扩展欧几里德算法: 基本算法:对于不完全为 0 的非负整数 a,b,gcd(a,b)表示 a,b 的最大公约数,必然存在整数对 x,y ,使

题解: poj 1061 nefu 84(拓展欧几里得)

POJ1061 Language:Default 青蛙的约会 Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 105002 Accepted: 20595 Description 两只青蛙在网上相识了,它们聊得很开心,于是觉得很有必要见一面.它们很高兴地发现它们住在同一条纬度线上,于是它们约定各自朝西跳,直到碰面为止.可是它们出发之前忘记了一件很重要的事情,既没有问清楚对方的特征,也没有约定见面的具体位置.不过青蛙们都是很乐观

[zoj 3774]Power of Fibonacci 数论(二次剩余 拓展欧几里得 等比数列求和)

Power of Fibonacci Time Limit: 5 Seconds      Memory Limit: 65536 KB In mathematics, Fibonacci numbers or Fibonacci series or Fibonacci sequence are the numbers of the following integer sequence: 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, .

拓展欧几里得详解 及其题目 POJ 1061 2115 2142 UVA 10673 10090

最近做了一些拓展欧几里得的题目呢,嘛,从一开始的不会到现在有点感觉,总之把我的经验拿出来和大家分享一下吧. 普通的欧几里得是用于解决求两个数a,b的gcd的,但是我们知道,gcd是线性组合 { ax+by | x,y∈Z }里的最小正元素(什么?不知道怎么来的?好吧...算法导论里数论算法那一章有证明),假若我们能够把这个x和y找出来,那么可以用来解决很多问题. (以下的gcd和lcm均指(gcd(a,b)和lcm(a,b)) 首先,假设ax+by=gcd这一个方程有一个特解x*,y*.那么显然

(转)拓展欧几里得讲解

拓展欧几里得 扩展欧几里得算法介绍: 前置知识:欧几里得算法(其实就是辗转相除法,用于计算两个整数a,b的最大公约数.) 欧几里得算法: 在开始之前,我们先说明几个定理: gcd(a,b)=gcd(b,a)=gcd(-a,b)=gcd(|a|,|b|) 公式表述及证明 gcd(a,b)=gcd(b,a mod b) 证明:a可以表示成a = kb + r,则r = a mod b 假设d是a,b的一个公约数,则有 d|a, d|b,而r = a - kb,因此d|r 因此d是(b,a mod b

拓展欧几里得求逆元与阶乘逆元求法

目录 什么是逆元 如何求逆元 阶乘逆元 本文章内,若无特殊说明,数字指的是整数,除法指的是整除. 什么是逆元 我们称\(a\)是\(b\)在模\(p\)情况下的逆元,则有\(a \times b \equiv 1 ( mod\,\,p)\). 所以呢,我们其实可以将逆元看成一个数的相反数.所以在除以一个数的时候,就相当于乘上它的相反数. 如何求逆元 我们先来看看什么情况下有逆元. 当且仅当\(gcd(b,p)=1\)时,\(b\)在模\(p\)情况下有逆元. 这个结论可由裴蜀定理显然推得,下面一