这两天都没什么东西做出来的../.T_T
第一次接触到逆元是11年大连的最后一题.囧啊,不会..什么都不会,网赛z怎么破
比如: (8/2)%5
我们求a*b*c*d*e*f*g..../z 前面乘积部分LL存不下所以要一边mod一边乘
最后处理到除z时,不一定能除尽
比如前面那个例子,8/5=3,3除不尽2就乘以2%5的逆元在%5
2%5的逆元=2^(5-2)=8 这是计算逆元的一种方法,后面讲。还有一直哦你方法是扩展欧几里德算法也是后面详细讲。
(3*8)%5=4=4%5
===
在计算(a/b)%Mod时,往往需要先计算b%Mod的逆元p(b有逆元的条件是gcd(b,Mod)==1,显然素数肯定有逆元),然后由(a*p)%Mod得结果c。这里b的逆元p满足(b*p)%Mod=1。先来简单证明一下:
(a/b)%Mod=c; (b*p)%Mod=1; ==》 (a/b)*(b*p) %Mod=c; ==》 (a*p)%Mod=c;
从上面可以看出结论的正确性,当然这里b需要是a的因子。接下来就需要知道根据b和Mod,我们怎么计算逆元p了。扩展欧几里德算法,大家应该都知道,就是已知a、b,求一组解(x,y)使得a*x+b*y=1。这里求得的x即为a%b的逆元,y为b%a的逆元(想想为什么?把方程两边都模上b或a看看)。调用ExtGcd(b,Mod,x,y),x即为b%Mod的逆元p。
求b%Mod的逆元p还有另外一种方法,即p=b^(Mod-2)%Mod,因为b^(Mod-1)%Mod=1(这里需要Mod为素数)。
以上来自:http://hi.baidu.com/zhanggmcn/item/ef4dadceb4fb993e449416e7
如例子 3/2%5=4; 2*3%5=1 ==> (3/2)*(2*8)%5=4 ==> (3*8)%5=4
===
关于扩展欧几里德:
首先扩展欧几里德主要是用来与求解线性方程相关的问题,所以我们从一个线性方程开始分析。现在假设这个线性方程为a*x+b*y=m,如果这个线性方程有解,那么一定有gcd(a,b) | m,即a,b的最大公约数能够整除m(m%gcd(a,b)==0)。证明很简单,由于a%gcd(a,b)==b%gcd(a,b)==0,所以a*x+b*y肯定能够整除gcd(a,b),如果线性方程成立,那么就可以用m代替a*x+b*y,从而得到上面的结论,利用上面的结论就可以用来判断一个线性方程是否有解。
那么在a*x+b*y=m这个线性方程成立的情况下,如何来求解x和y呢?
1.令a1=a/gcd(a,b),b1=b/gcd(a,b),m1=m/gcd(a,b)。如果我们能够首先求出满足a*x1+b*y1=gcd(a,b)这个方程的x1和y1,那么x=x1*m1,y=y1*m1就可以求出来了。由欧几里德算法gcd(a,b)=gcd(b,a%b),所以a*x1+b*y1=gcd(a,b)=gcd(b,a%b)=b*x2+(a%b)*y2,现在只要做一些变形就可以得到扩展欧几里德算法中的用到的式子了。令k=a/b(商),r=a%b(余数),那么a=k*b+r。所以r=a-k*b,带入上式,得到a*x1+b*y1=b*x2+(a-(a/b)*b)y2=a*y2+b*(x2-(a/b)*y2) => x1=y2,y1=x2-(a/b)*y2。有了这两个式子我们就知道了在用欧几里德求最大公约数的时候,相应的参数x,y的变化。现在再回过头来看一下扩展欧几里德算法的代码就很好理解了,实际上扩展欧几里德就是在求a和b的最大公约数的同时,也将满足方程a*x1+b*y1=gcd(a,b)的一组x1和y1的值求了出来。下面代码中突出的部分就是标准的欧几里德算法的代码。
__int64 exGcd(__int64 a,__int64 b,__int64 &x,__int64 &y){ if(b==0){ x=1; y=0; return a; } __int64 g=exGcd(b,a%b,x,y); __int64 temp=x; x=y; y=temp-(a/b)*y; return g; }
===
扩展欧几里德求逆元模板: #include<iostream> #define __int64 long long using namespace std; //举例 3x+4y=1 ax+by=1 //得到一组解x0=-1,y0=1 通解为x=-1+4k,y=1-3k inline __int64 extend_gcd(__int64 a,__int64 b,__int64 &x,__int64 &y)//ax+by=1返回a,b的gcd,同时求的一组满足题目的最小正整数解 { __int64 ans,t; if(b==0){x=1;y=0;return a;} ans=extend_gcd(b,a%b,x,y);t=x;x=y;y=t-(a/b)*y; return ans; } //(a/b)%mod=c 逆元为p,(p*b)%mod=1 //(a/b)*(p*b)%mod=c*1%mod=c // (p*b)%mod=1 等价于 p*b-(p*b)/mod*mod=1其中要求p,b已知 等价于 ax+by=1 //其中x=p(x就是逆元),y=p/mod,a=b,b=b*mod 那么调用extend_gcd(b,b*mod,x,y)即可求(a/b)%mod的逆元等价于a*p%mod int main() { __int64 a,b,x,y,c,gcd,mod,p;//ax+by=c while(cin>>a>>b>>c) { gcd=extend_gcd(a,b,x,y); cout<<x<<" "<<y<<endl; if(c%gcd){cout<<"无解!"<<endl;continue;} cout<<"x="<<x*c/gcd<<" y="<<y*c/gcd<<endl; } return 0; }
===
根据大连I题和大神代码..再改了一个一个模板:
贴上模板:
#include <iostream> using namespace std; int x,y,rev;
void extend_Euclid(int a, int b) { if(b==0) { x = 1; y = 0; return; } extend_Euclid(b, a%b); int t = x; x = y; y = t - a/b*y; } int main() { //b%mod的逆元 int b,mod; while(cin>>b>>mod){ // x=0;y=0; extend_Euclid(b,mod); cout<<(x%mod+mod)%mod<<endl; } return 0; }