模运算
几个常用的定律:
( a + b ) mod p = ( a mod p + b mod p ) mod p
( a * b ) mod p = ( (a mod p) * (b mod p) ) mod p
c * ( a mod p ) = ( c *a ) mod ( c *b )
扩展欧几里得
void Exgcd(ll a, ll b, ll &x, ll &y) {
if (!b) x = 1, y = 0;
else Exgcd(b, a % b, y, x), y -= a / b * x;
}
int main() {
ll x, y;
Exgcd (a, p, x, y);
x = (x % p + p) % p;
printf ("%d\n", x); //x是a在mod p下的逆元
}
这个做法要利用 费马小定理
若 p 为素数, a 为正整数,且 a 、 p 互质。 则有
。
这个我们就可以发现它这个式子右边刚好为 11 。
所以我们就可以放入原式,就可以得到:
a∗x≡1(mod p)
所以我们可以用快速幂来算出的值,这个数就是它的逆元了
代码也很简单:
ll fpm(ll x, ll power, ll mod) {//快速幂求乘法逆元,谨记,p是一个素数
x %= mod;
ll ans = 1;
for (; power; power >>= 1, (x *= x) %= mod)
if(power & 1) (ans *= x) %= mod;
return ans;
}
int main() {
ll x = fpm(a, p - 2, p); //x为a在mod p意义下的逆元
}
这里有一个模板题目,就是洛谷的 P3811 【模板】乘法逆元
题目传送门:https://www.luogu.org/problemnew/show/P3811
#include
#include
#include
using namespace std;
long long x,y,n,f[3000010];
void work(long long n,long long p)//线性求逆元,时间复杂度O(n)
{
f[1]=1;
for(long long i=2;i<=n;i++)
{
f[i]=-(p/i)*f[p%i];
f[i]=(f[i]%p+p)%p;
}
}
int main()
{
long long a,p,b,n,i;
cin>>n>>p;
work(n,p);
for(long long i=1;i<=n;i++)
{
printf("%lld\n",f[i]);//处理出 最小正整数!!
}
return 0;
}
扩展欧几里得模板
#define ll long long int
ll a,b,x,y;
void exgcd(ll a,ll b,ll &x,ll &y){//扩展欧几里得模板
if(!b)//b==0
x=1,y=0;
else
exgcd(b,a%b,y,x),y-=a/b*x;
}
long long x,y,n;//最好定全局变量
void exgcd(long long a,long long b)//也适合javaer
{
if(b==0) //当b=0时就是遇到了特解,可以递归回去算答案了
{
x=1,y=0;
return ;
}
exgcd(b,a%b);
long long k;
k=x;
x=y;
y=k-(a/b)*y;
}
求关于x的同余方程 的最小正整数解。
输入格式:
一行,包含两个正整数 a,ba,b,用一个空格隔开。
输出格式:
一个正整数 x0,即最小正整数解。输入数据保证一定有解。
输入样例#1: 复制
3 10
输出样例#1: 复制
7
【数据范围】
对于 40%的数据,2 ≤b≤ 1,000;
对于 60%的数据,2 ≤b≤ 50,000,000;
对于 100%的数据,2 ≤a, b≤ 2,000,000,000。
NOIP 2012 提高组 第二天 第一题
扩展欧几里得模板
#include
#include
using namespace std;
#define ll long long int
ll a,b,x,y;
void exgcd(ll a,ll b,ll &x,ll &y){//扩展欧几里得模板
if(!b)//b==0
x=1,y=0;
else
exgcd(b,a%b,y,x),y-=a/b*x;
}
int main(){
ios::sync_with_stdio(false);
while(~scanf("%d%d",&a,&b)){
exgcd(a,b,x,y);
cout<<(x%b+b)%b;
}
return 0;
}
欧拉函数+快速幂写法 复杂度O(logn+sqrt(n)) 好处 ax=1(mod b) 不需要a,b互
#include
#include
using namespace std;
#define ll long long int
ll Euler(ll n){//O(sqrt(n))
ll ans = n;
for(int i=2;i*i<=n;i++)
if(n%i==0){
ans = ans/i*(i-1);
while(n%i==0)
n/=i;
}
if(n>1)
ans = ans/n*(n-1);
return ans;
}
ll mod_pow(ll a,ll n,ll mod){
ll ans = 1;
while(n>0){
if(n%2==1)
ans = ans*a%mod;
a = a*a%mod;
n>>=1;
}
return ans;
}
int main(){//ax=1(mod b)
ll a,b;
while(~scanf("%lld%lld",&a,&b)){
printf("%lld\n",mod_pow(a,Euler(b)-1,b));
}
return 0;
}
kuangbin模板——扩展欧几里得
//返回d=gcd(a,b);和对应于等式ax+by=d中的x,y
long long extend_gcd(long long a,long long b,long long &x,long long &y)
{
if(a==0&&b==0) return -1;//无最大公约数
if(b==0){x=1;y=0;return a;}
long long d=extend_gcd(b,a%b,y,x);
y-=a/b*x;
return d;
}
//*********求逆元素*******************
//ax = 1(mod n)
long long mod_reverse(long long a,long long n)
{
long long x,y;
long long d=extend_gcd(a,n,x,y);
if(d==1) return (x%n+n)%n;
else return -1;
}
Problem Description
要求(A/B)%9973,但由于A很大,我们只给出n(n=A%9973)(我们给定的A必能被B整除,且gcd(B,9973) = 1)。
Input
数据的第一行是一个T,表示有T组数据。
每组数据有两个数n(0 <= n < 9973)和B(1 <= B <= 10^9)。
Output
对应每组数据输出(A/B)%9973。
Sample Input
2
1000 53
87 123456789
Sample Output
7922
6060
扩展欧几里得
#include
#include
using namespace std;
#define MOD 9973
#define ll long long int
ll exgcd(ll a,ll b,ll &x,ll &y){
if(a==0 && b==0)
return -1;//无最大公约数
if(b==0){
x=1;
y=0;
return a;
}
ll d = exgcd(b,a%b,y,x);
y-=a/b*x;
return d;
}
//ax=1(mod n)
ll mod_reverse(ll a,ll n){
ll x,y;
ll d = exgcd(a,n,x,y);
if(d==1)
return (x%n+n)%n;
else
return -1;
}
int main(){
ll n,b;
int T;
scanf("%d",&T);
while(T--){
scanf("%lld%lld",&n,&b);
ll x = mod_reverse(b,MOD);
printf("%lld\n",n*x%MOD);
}
return 0;
}
费马小定理+快速幂
#include
#include
using namespace std;
#define ll long long int
#define MOD 9973
ll mod_pow(ll a,ll n,ll mod){
ll ans = 1;
while(n>0){
if(n%2==1)
ans = ans*a%mod;
a = a*a%mod;
n>>=1;//右移
}
return ans;
}
int main(){
int T;
ll n,b;
scanf("%d",&T);
while(T--){
scanf("%lld%lld",&n,&b);
b = mod_pow(b,MOD-2,MOD);
b = (b%MOD+MOD)%MOD;
printf("%lld\n",n*b%MOD);
}
return 0;
}