1.一些定理及证明
1.费马小定理
若p为素数,则有
2.欧拉定理
若a,p互质,则有
证明:
令为p的欧拉函数
设a mod p的简化剩余系为
因为a,p互质,所以a*p一定在a mod p的简化剩余系里
故
所以 , 故欧拉定理成立
因为p为质数,所以
故 ,费马小定理成立
欧拉定理的推论:若a,p互质,则有
证明:令 ,
故 ,推论成立
2.拓展欧几里得
1.bezout定理:一定存在整数使ax+by=gcd(a,b)
证明 当b=0时,x=1,y=0,命题成立
当b!=0时,gcd(a,b)=gcd(b,a mod b)
假设有一组解使ax+by=gcd(b,a mod b)成立
令
故
故
所以一定有一组整数解为
实现代码:
int exgcd(int a,int b,&x,&y){
if(!y){
x=1,y=0;
return a;
}
int gcd=exgcd(b,a%b,x,y);
int ty=x;
x=y,y=ty-a/b*y;
return gcd;
}
对于一般的不定方程ax+by=d,当且仅当 gcd(a,b)|d时方程有整数解
一组整数解为
所有整数解为
证明:gcd(a,b)|a,gcd(a,b)|b
所以新的x,y一定是整数
将 带入不定方程
因为
解得
逆元
因为除法运算不能取模,所以需要找到一个合适的工具来代替取模运算中的除法,就引进了逆元
,inv就是x在模m意义下的逆元
在模m的意义下,x*inv的值是1,就相当于x*1/x,同理,k为任意整数,k*inv在模m的意义下就相当于k*1/x
当且仅当x与m互质的情况下才有逆元
证明:
根据bezout定理,当且仅当gcd(x,m)|1时方程有解
故gcd(x,m)=1,也就是x与m互质
3.中国剩余定理
设m1,m2,m3...两两互质,且
求x最小值
令
则
证明:对于i=k时,m/m[i]保证了这个答案加上对其他项没有影响,其他保证了这一项加上后在ans对m[i]取模时答案为a[i](m/m[i]*inv在模m[i]的意义下余1,故这个式子在模m[i]的情况下为a[i]
for(int i=1;i<=n;i++){
ll mi=mulmod/a[i];
ll x,y;
ll gcd=exgcd(mi,m[i],x,y);//求出在模m[i]意义下的逆元
x=(x%m[i]+m[i])%m[i];
ans+=mi*x*a[i];
}
4.拓展中国剩余定理
还是这种形式,但是模数不一定互质,这时候就不能用中国剩余定理了
因为若余数不两两互质, m/m[i]就不会和m[i]互质,就找不到
所以中国剩余定理就不再适用
这时考虑构造特解,对于 ,令
,ans为前i-1组方程的解
那么需要找到一个x使 ,那么ans+x*lcm一定是前i组方程的通解
因为
就需要求出x的值,然后用ans+x*lcm更新ans
mul=1;
for(int i=1;i<=n;i++){
ll gcd=exgcd(mul,b[i],x,y);
ll d=a[i]-ans;
x=x*(d/gcd);
ll ty=b[i]/gcd;
x=(x%ty+ty)%ty;
ans=ans+x*mul;
mul=b[i]/exgcd(b[i],mul,x,y)*mul;
}
继续拓展
继续构造解,对于 , 令
,ans为前i-1组方程的解
那么需要找到一个x使 ,那么ans+x*lcm一定是前i组方程的通解
因为
求出x,并且使ans=ans+x*lcm
其他部分实现都很简单吧
#include<bits/stdc++.h>
using namespace std;
typedef __int128 ll;
ll read();
void write(ll x);
int t;
ll a[100010],b[100010],p[100010],jl[100010],n,m;
ll x,y,ans,mul;
void excrt();
ll exgcd(ll a,ll b,ll &x,ll &y);
int main(){
scanf("%d",&t);
while(t--){
ans=0;
mul=1;
n=read(),m=read();
for(int i=1;i<=n;i++) a[i]=read();
for(int i=1;i<=n;i++) p[i]=read();
for(int i=1;i<=n;i++) jl[i]=read();
for(int i=1;i<=m;i++) b[i]=read();
if(p[1]==1){
multiset<int>s;
s.clear();
for(int i=1;i<=m;i++) s.insert(b[i]);
for(int i=1;i<=n;i++){
multiset<int>::iterator it=s.upper_bound(a[i]);
it==s.begin()?it:it--;
s.erase(it);
ll bnow=(*it);
ans=max(ans,(ll)ceil((double)a[i]/bnow));
s.insert(jl[i]);
}
write(ans);
}
else{
excrt();
if(ans!=-1) write(ans);
else printf("-1");
}
putchar('\n');
}
return 0;
}
void excrt(){
multiset<ll>s;
s.clear();
for(int i=1;i<=m;i++) s.insert(b[i]);
for(int i=1;i<=n;i++){
multiset<ll>::iterator it=s.upper_bound(a[i]);
if(it!=s.begin()) it--;
s.erase(it);
ll bnow=(*it);
ll gcd=exgcd(mul*bnow,p[i],x,y);
ll d=(a[i]-ans*bnow%p[i]+p[i])%p[i];
if(d%gcd){
ans=-1;
return ;
}
x=x*(d/gcd);
ll ty=p[i]/gcd;
x=(x%ty+ty)%ty;
ans+=mul*x;
mul=mul*(p[i]/gcd);
s.insert(jl[i]);
}
ans=(ans%mul+mul)%mul;
}
ll exgcd(ll a,ll b,ll &x,ll &y){
if(!b){
x=1,y=0;
return a;
}
ll gcd=exgcd(b,a%b,x,y);
ll ty=x;
x=y,y=ty-a/b*y;
return gcd;
}
ll read(){
ll a=0;
char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9') a=a*10+ch-'0',ch=getchar();
return a;
}
void write(ll x){
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
本文探讨了费马小定理和欧拉定理的基本原理及其证明,包括欧拉函数、简化剩余系的应用,以及这些定理在拓展欧几里得和中国剩余定理中的关键角色。通过实例和代码展示了如何利用这些理论解决实际问题,如求逆元和求解不定方程。


被折叠的 条评论
为什么被折叠?



