中国剩余定理
参考资料
简介
中国剩余定理 (Chinese Remainder Theorem,CRT) 可求解如下形式的一元线性同余方程组:
其中 两两互质。
例题
洛谷 P1495 【模板】中国剩余定理(CRT)/ 曹冲养猪
自从曹冲搞定了大象以后,曹操就开始捉摸让儿子干些事业,于是派他到中原养猪场养猪,可是曹冲满不高兴,于是在工作中马马虎虎,有一次曹操想知道母猪的数量,于是曹冲想狠狠耍曹操一把。举个例子,假如有 头母猪,如果建了 个猪圈,剩下 头猪就没有地方安家了。如果建造了 个猪圈,但是仍然有 头猪没有地方去,然后如果建造了 个猪圈,还有 头没有地方去。你作为曹总的私人秘书理所当然要将准确的猪数报给曹总,你该怎么办?
代码(3)
- CRT
- EXCRT
- 枚举
#include <bits/stdc++.h>
using namespace std;
using ll=long long;
const int N=15;
tuple<ll,ll,ll> exgcd(ll a,ll b)
{
if(!b)return {a,1,0};
auto [g,x,y]=exgcd(b,a%b);
return {g,y,x-a/b*y};
}
ll a[N],b[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin>>n;
__int128 sum=1;
for(int i=1;i<=n;i++)
{
cin>>a[i]>>b[i];
sum*=a[i];
}
__int128 ans=0;
for(int i=1;i<=n;i++)
{
ll k=sum/a[i];
auto [g,x,y]=exgcd(k,a[i]);
ans=(ans+k*x%sum*b[i]%sum+sum)%sum;
}
cout<<ll(ans)<<'\n';
return 0;
}
#include <bits/stdc++.h>
using namespace std;
using ll=long long;
tuple<ll,ll,ll> exgcd(ll a,ll b)
{
if(!b)return {a,1,0};
auto [g,x,y]=exgcd(b,a%b);
return {g,y,x-a/b*y};
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin>>n;
__int128 ans=0,sum=1;
while(n--)
{
ll a,b;
cin>>a>>b;
auto [g,x,y]=exgcd(sum,a);
ans-=(ans-b)/g*x*sum;
sum*=a/g;
ans=(ans%sum+sum)%sum;
}
cout<<ll(ans)<<'\n';
return 0;
}
#include <bits/stdc++.h>
using namespace std;
using ll=long long;
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin>>n;
ll ans=0,sum=1;
while(n--)
{
ll a,b;
cin>>a>>b;
while(ans%a!=b)ans+=sum;
sum*=a;
}
cout<<ans<<'\n';
return 0;
}
洛谷 P4777 【模板】扩展中国剩余定理(EXCRT)
给定 组非负整数 ,求解关于 的方程组的最小非负整数解。
代码(1)
#include <bits/stdc++.h>
using namespace std;
using ll=long long;
tuple<ll,ll,ll> exgcd(ll a,ll b)
{
if(!b)return {a,1,0};
auto [g,x,y]=exgcd(b,a%b);
return {g,y,x-a/b*y};
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin>>n;
__int128 ans=0,sum=1;
while(n--)
{
ll a,b;
cin>>a>>b;
auto [g,x,y]=exgcd(sum,a);
ans-=(ans-b)/g*x*sum;
sum*=a/g;
ans=(ans%sum+sum)%sum;
}
cout<<ll(ans)<<'\n';
return 0;
}