若a*x≡1(mod b) a,b互质,则称x为a的逆元,记为a-1。在计算(t/a)mod b 时等价于t*a-1mod b。
显然可转化为ax+by=1,用扩欧来求解,但相对来说是比较慢的,这里还有线性算法:
首先1-1≡1(mod p)
设p=k*i+r,那么k*i+r≡0(mod p)两边同乘i-1,r-1,可得在mod p 意义下:
k*r-1+i-1≡0
→i-1≡-k*r-1
→i-1≡-(p/i)*(p mod i)-1
于是我们就求得了递推式:a[i]=-(p/i)*a[p%i](a[1]=1,因为p%i<i所以a[p%i]会在之前求出)
就可线性求解乘法逆元:
1.板子
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; int n,p,a[3000010]; int main() { scanf("%d%d",&n,&p); a[1]=1; for(int i=2;i<=n;i++) a[i]=-(long long)(p/i)*a[p%i]%p; for(int i=1;i<=n;i++) { if(a[i]<0)a[i]+=p; printf("%d\n",a[i]); } }
例题:
[AHOI2005]洗牌:
我们先按样例找下规律:
1,4,2,1
2,1,4,2
3,5,6,3
4,2,1,4
5,6,3,5
6,3,5,6
//每一列代表一次洗牌。
我们发现每次的位置变化为当前位置*2再取余(n+1),
设当前位置为x
那么下一次位置为2*x%(n+1)
下m次位置为2m*x%(n+1)
我们要求的就是满足2m*x≡l (mod n+1)的x.
那么x≡l*(2m)-1(mod n+1)
所以只要求出2m在模n+1意义下的逆元就可以求出x
代码如下:
#include<iostream> #include<cstdio> #include<algorithm> #define mod (n+1) using namespace std; int n,l,m,x,y; int _pow(int x,int y) { int ans=1; for(;y;y>>=1) { if(y&1) ans=(long long)ans*x%(n+1); x=(long long)x*x%(n+1); } return ans%(n+1); } void exgcd(int a,int b) { if(b==0) { x=1; y=0; return; } exgcd(b,a%b); x^=y^=x^=y; y-=a/b*x; } int main() { scanf("%d%d%d",&n,&m,&l); int a=_pow(2,m); exgcd(a,n+1); while(x<=0)x+=n+1; if((long long)x*l%(n+1)==0) { cout<<n+1; return 0; } printf("%lld",(long long)x*l%(n+1)); }