基础数论算法(三) 逆元和gcd的几道题

来源:互联网 发布:淘宝质量好的女装店 编辑:程序博客网 时间:2024/05/21 12:03

参考:http://blog.csdn.net/acdreamers/article/details/8220787


逆元

先来说说逆元是什么。我们知道,(a*b)%c=((a%c)(b%c))%c,这为我们快速幂什么的带来了非常大的方便。那么a/b呢?显然(a/b)%c不满足乘法一样的性质,那么我们有一个便利的工具:(a/b)%c=(a*b1)%c。这里的b1不是指代1b,而是b的逆元
逆元的标准定义是这样的:若ax1(mod b)且a,b互质,则x为a的逆元。类似这样的线性同余方程显然可以直接用exgcd求。详见上一期。
还有一种可以求出一张逆元表的O(n)做法:
A[i]=-(p/i)*A[p%i],特别的当i=1时A[i]=1

接下来的证明大可不看
p0(mod  p)
p=ki+r,1<r<i<p
ki+r0
iir1
kr1+i10
i1kr1
i1pi(p%i)1
QED

虽然蛮好写的不过不太好记orz
不过不要担心,有这样一个非常好用的公式足以应付大多数需要逆元的问题:

am%c=a%(mc)m


几道例题

1、codefoeces837E Vasya的函数
设f(x,y),若y=0,则f(x,0)=0,否则f(x,y)=f(x,y-gcd(x,y))。 求f(x,y)
朴素会T在3点,具体解法看在下的题解吧orz

2、欧几里得的游戏
两个无聊的人在玩一个无聊的游戏。据传这是欧几里得发明。规则是这样的:先选两个数A,B,从甲开始从较大数中选较小数的k倍,之后同理双方交换。先得到0的一方获得胜利,现在给出A,B,若两人足够聪明,那么谁将获胜?
游戏的最优化问题不管会不会做,总之先脑内yy一局。
说点题外话。不知道各位有没有玩过拿东西的那个游戏?最多能取4支什么的,我们的必胜策略就是取到(5-n)支。其实这个是有些类似的:只要我们先手能用类似的办法控制住主动权,就相当于找到了一种必胜策略。
好,那如何取得主动权?拿东西是给出了能拿几个,而事实上欧几里得的游戏就是需要计算能拿几个的拿东西。我们不妨这样思考:
假设某一状态下,x>y,轮到A,如果xy>1,那么A拿走(xy1)×y,就相当于逼迫着B只能拿一个,这样就将主动权掌握了,但是!如果xy=1,那么就相当于主动权反过来了,因为下一局就会占有有利地位。
但先手的人足够狡(wu)猾(liao)。显然我们知道,这样的主动权交换如果是奇数次那么交换半天就会回来完全不用担心,而如果是偶数次,先拿到最后一个>1状态的的人完全可以全部拿光一点不剩,这样=1状态又成为了1.所以,我们得出结论:谁先得到>1状态就是谁的胜利!至于谁先拿到,立个flag即可。那就非常简单了:

#include <iostream>using namespace std;typedef long long LL;int main(){    LL x,y;    cin>>x>>y;    if(x<y) swap(x,y);    short flag=1;LL t;    while(x%y&&x/y==1){        flag=-flag;        t=x%y;        x=y;        y=t;                    }    if(flag==1) cout<<"A"<<endl;    else cout<<"B"<<endl;    return 0;}

3、[POJ1061]青蛙的约会
有两只青蛙网恋了,现在他们在某一个球体上。假定某一点为原点,某一方向为正方向,我们得到了一个环形数轴。现在青蛙A在x点,B在y点,A速度m,B速度n,数轴全长L,求能不能碰上需要跳几次碰上。
首先不要想着去模拟,因为模拟是绝对没有办法判断出来能不能碰上的(笑)。
那么根据小学数学,我们轻而易举的列出来这么一个方程:
(x+m·t)-(y+n·t)=p·L
显然用exgcd能求出来t,p。为了方便代,我们不妨先整理一下:
(n-m)t+pL=x-y
要求条件:(x-y)%gcd(n-m,L)=0
最小正整数解:t=(t%m+m%t,其中m=Lgcd(L,nm)
(详情见上次的)
实现就不细说了,反正都是套路

4.[POJ1845]因子和
AB所有因子之和并取模9901。
首先需要一个定理
分解质因数后若A=pk11pk22pk33pk44...pknn
则因数和

S=(1+p1+p21+......+pk11)(1+p2+p22+......+pk22)(1+p3+p23+......+pk33)(1+p4+p24+......+pk44)...(1+pn+p2n+......+pknn)

好,再进行一次变形,带等比数列求和公式:
S=(pk111p11)(pk221p21)(pk331p31)(pk441p41)...(pknn1pn1)

注意每一次求和都要取模,商的取模只要用逆元即可。
还记得我们之前讲过的快速幂取模模板吗?这里可是大活跃呢。
好,再思考一件事:AB,如果A=pk11pk22pk33pk44...pknn,那它的结果不就是每一项的指数上乘个B么。
并且各位应该还记得,(A+B)%m=(A%m+B%m)%m,(A·B)%m=(A%m·B%m)%m,把这些统一到一起,做法就呼之欲出了。代码就不写了orz 其实是还在调试中来着不知道哪里写错了qwq

阅读全文
0 0
原创粉丝点击