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;
}