2021.08.11 拓展欧几里得、逆元与同余

详情参考《初等数论1》第三章、第四章

练习题:

UVA10104 Euclid Problem - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;

typedef long long ll;
ll a,b;

inline ll read(){
	ll s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')w=-1;
		ch=getchar();
	}
	while(ch<='9'&&ch>='0'){
		s=s*10+ch-'0';
		ch=getchar();
	}
	return s*w;
}
ll exgcd(ll a,ll b,ll &x,ll &y){
	if(!b)return x=1,y=0,a;
	ll c=exgcd(b,a%b,x,y);
	ll ls=x;
	x=y;
	y=ls-(a/b)*y;
	return c;
}

int main(){
	while(~scanf("%lld%lld",&a,&b)){
		//cout<<"   case 1"<<endl;
		ll x,y;
		ll gcd=exgcd(a,b,x,y);
		cout<<x<<" "<<y<<" "<<gcd<<endl;
		//cout<<"   case 2"<<endl;
	}
	return 0;
}

UVA12775 Gift Dilemma - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

//还是美丽的exgcd,刚写过~UVA10104
//外加不定方程
//ax+by+cz=p->ax+by=p-cz,枚举z
//详情参考《初等数论1》 
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<iostream>
using namespace std;

typedef long long ll; 
ll t,a,b,c,p,x,y,ans;

inline ll read(){
	ll s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')w=-1;
		ch=getchar();
	}
	while(ch<='9'&&ch>='0'){
		s=s*10+ch-'0';
		ch=getchar();
	}
	return s*w;
}
ll exgcd(ll a,ll b,ll &x,ll &y){
	if(!b)return x=1,y=0,a;
	ll ls=exgcd(b,a%b,x,y);
	ll xi=x;
	return x=y,y=xi-(a/b)*y,ls; 
}
ll gcd(int x,int y){
	return y==0?x:gcd(y,x%y);
}

int main(){
	//freopen("1.in","r",stdin);
	//freopen("1.out","w",stdout);
	t=read();
	int js=0;
	while(t--){
		++js;
		a=read();b=read();c=read();p=read();
		x=y=ans=0;
		ll d=exgcd(a,b,x,y); 
		for(ll i=0;i*c<=p;i++){
			ll yu=p-i*c;
			if(yu%d)continue;
			ll x0=x*yu/d,y0=y*yu/d;
			ans+=(floor(1.0*x0*d/b)-ceil(-1.0*y0*d/a)+1);
		}
		printf("Case %lld: %lld\n",js,ans);
		//if(t!=1)cout<<endl;
	}
	return 0;
}

[P1082 NOIP2012 提高组] 同余方程 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;

typedef long long ll;
ll a,b,x,y;

inline ll read(){
	ll s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')w=-1;
		ch=getchar();
	}
	while(ch<='9'&&ch>='0'){
		s=s*10+ch-'0';
		ch=getchar();
	}
	return s*w;
}
void exgcd(ll a,ll b,ll &x,ll &y){
	if(!b){
		x=1,y=0;
		return ;
	}
	exgcd(b,a%b,x,y);
	ll xi=x;
	x=y;y=xi-(a/b)*y;
}

int main(){
	a=read();b=read();
	exgcd(a,b,x,y);
	//x=x0-bt>=0不断减b
	x=(x%b+b)%b;
	cout<<x;
	return 0; 
}

B2086 不定方程求解 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;

int a,b,c,x,y;

inline int read(){
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')w=-1;
		ch=getchar();
	}
	while(ch<='9'&&ch>='0'){
		s=s*10+ch-'0';
		ch=getchar();
	}
	return s*w;
}
int exgcd(int a,int b,int &x,int &y){
	if(!b)return x=1,y=0,a;
	int d=exgcd(b,a%b,x,y);
	int xi=x;
	return x=y,y=xi-(a/b)*y,d;
}

int main(){
	a=read();b=read();c=read(); 
	int d=exgcd(a,b,x,y);
	if(c%d)return cout<<"0",0;
	int x0=x*(c/d),y0=y*(c/d);
	int ans=floor(1.0*x0*d/b)-ceil(-1.0*y0*d/a)+1;
	cout<<ans;
	return 0;
}

P1516 青蛙的约会 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;

#define int long long
int n,m,xi,yi,l,x,y,a,b,ans;

inline int read(){
    int s=0,w=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-')w=-1;
        ch=getchar();
    }
    while(ch<='9'&&ch>='0'){
        s=s*10+ch-'0';
        ch=getchar();
    }
    return s*w;
}
inline int exgcd(int a,int b,int &x,int &y){
	if(!b)return x=1,y=0,a;
	int c=exgcd(b,a%b,x,y);
	int xi=x;
	return x=y,y=xi-(a/b)*y,c;
}

signed main(){
	xi=read();yi=read();m=read();n=read();l=read();
	a=xi-yi,b=n-m;
	if(b<0)b=-b,a=-a;
	ans=exgcd(b,l,x,y);
	//cout<<ans<<" "<<x<<endl;
	if(a%ans)puts("Impossible");
	else cout<<((x*(a/ans))%(l/ans)+(l/ans))%(l/ans);
	return 0;
}

#110. 乘法逆元 - 题目 - LibreOJ (loj.ac)

#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;

#define int long long
int n,p,inv[3000010];

inline int read(){
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')w=-1;
		ch=getchar();
	}
	while(ch<='9'&&ch>='0'){
		s=s*10+ch-'0';
		ch=getchar();
	}
	return s*w;
}

signed main(){
	n=read();p=read();
	inv[1]=1;
	cout<<inv[1]<<endl;
	for(int i=2;i<=n;i++){
		inv[i]=(p-p/i)*inv[p%i]%p;
		printf("%lld\n",inv[i]);
	}
	return 0;
}

[P2054 AHOI2005]洗牌 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

//位置由x变为2x%(n-1),m次之后为2^m*x%(n-1) 
#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;

#define int long long
int n,m,k,x,y;

inline int read(){
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')w=-1;
		ch=getchar();
	}
	while(ch<='9'&&ch>='0'){
		s=s*10+ch-'0';
		ch=getchar();
	}
	return s*w;
}
/*int pow(int x,int y){
	int ans=1;
	//cout<<" x "<<x<<endl;
	while(y){
		if(y&1)ans=1ll*ans*x%(n+1);
		x=1ll*x*x%(n+1);
		y>>=1;
		//cout<<ans<<" "<<x<<endl;//
	}
	return ans;
} */
int mul(int a,int b){
	int ans=0;
	while(b){
		if(b&1)ans=(ans+a)%(n+1);
		a=(a+a)%(n+1);
		b>>=1;
	}
	return ans;
}
int pow(int a,int b){
	int ans=1;
	while(b){
		if(1&b)ans=mul(ans,a)%(n+1);
		a=mul(a,a)%(n+1);
		b>>=1;
	}
	return ans;
}
int exgcd(int a,int b,int &x,int &y){
	if(!b)return x=1,y=0,a;
	int d=exgcd(b,a%b,x,y);
	x^=y^=x^=y;
	y-=(a/b)*x;
	return d;
}

signed main(){
	n=read();m=read();k=read();
	int ai=pow(2,m);
	//cout<<a<<endl;
	exgcd(ai,n+1,x,y);
	while(x<0)x+=(n+1);
	cout<<mul(x,k);
	return 0;
}

P2613 【模板】有理数取余 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;

const int mod=19260817;
int a,b,x,y;

inline int read(){
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')w=-1;
		ch=getchar();
	}
	while(ch<='9'&&ch>='0'){
		s=s*10+ch-'0';s%=mod;
		ch=getchar();
	}
	return s*w%mod;
}
void exgcd(int a,int b,int &x,int &y){
	if(!b){
		x=1,y=0;
		return ;
	}
	exgcd(b,a%b,x,y);
	int xi=x;
	x=y;y=xi-(a/b)*y;
}
int gcd(int a,int b){
	return b==0?a:gcd(b,a%b);
}

int main(){
	a=read();b=read();
	if(!b||a%gcd(b,mod))return cout<<"Angry!",0;
	exgcd(b,mod,x,y);
	x=(x%mod+mod)%mod;
	x=1ll*a*x%mod;
	cout<<x;
	return 0;
}