중국 잉여 정리 CRT
유도
감안 \ N- (\) 번째 합동 식
\ [\ 좌측 \ {\ 시작 및 정렬 {X} 및 \ 당량 A_1 \ pmod에 m_1과 {} \\ X 및 \ 당량 A_2 \ pmod에 m_2 {}를 \\ ... X 및 \\ \ 당량 A_N \ M_n PMOD {} \ 배향 엔드 {} \ 오른쪽. \]
\ (m_1과, M_2, ... M_n \) 페어 질량令\ (M = \ {prod_ I = 1} ^ {N} m_i \) ,求\ (X \ 개조 M \)
이 문제에 대한 해결책은 구조이다.
우리는 최종의 형태로 대답 가정 \ (n \) 및 용어는 해당 용어의 반응 계수 각각 합동 식의 구조를 입력.
각 항목의 각 계수는 다른 식의 결과의 구성에 영향을주지 않도록, 적절한 수를 곱한 값에 대한 필요는, 각 항목에 대해 개별적으로 구성.
쉽게 구성 발생
\ [M_i = \ FRAC {M } {m_i} \]
물론이 숫자는 단지 아날로그 \ (m_i \) 와 동일하지 \ (0 \) , 다음 변경 계수가 다른 방정식없는 영향을 미칠 것이다.
이제 우리는 그 금형 희망 \ (m_i을 \) 의미에서 그 \ (A_I \) 하지만, 아래 마지막 남은 구조 \ (M_i \) . 승산 심플 조 \ (M_i \) 금형 \ (m_i는 \) 원의 의미를 반대로 \ (inv_ m_i {} (M_i) \) , 그래서 몰드 것을 \ (m_i는 \) 의 의미가된다 (\ 1 \) 다음 곱 (A_I \) \ 아웃 구축.
요약하면, 응답은
[\ sum_ {I = 1 \ } ^ {N} M_i inv_ m_i {} (M_i) A_I \ 개조 {M} \]
모듈로 주요 조건 보장하지만 그 \ (M_i \) 가 아닌 \ (0 \) 는 것을 보장하기 위해 \ (inv_ {m_i} (M_i가 ) \) 이 존재한다.
실현
모든 질문에 대부분의 \ (m_i \)는 소수, 역 찾을 수있다 \ (QPow을 \) 가 될 수 있습니다.
일반적인 경우를 들어, 라인에 exgcd.
보드 질문 : 루오 구 조충 돼지 P1495
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<vector>
#include<map>
#include<set>
using namespace std;
typedef long long ll;
namespace ExGcd{
ll x,y;
ll ExGcd(ll a,ll b){
ll ans;
if(a%b==0){
x=0;y=1;ans=b;
}else{
ans=ExGcd(b,a%b);
ll x1=x,y1=y;
x=y1;y=x1-a/b*y1;
}
return ans;
}
bool SolveEqu(ll a,ll b,ll c){
ll d=ExGcd(a,b);
if(c%d!=0) return 0;
x*=c/d;y*=c/d;
x=(x%b+b)%b;
y=(c-a*x)/b;
return 1;
}
}
ll Inv(ll a,ll m){
ExGcd::SolveEqu(a,m,1);
return ExGcd::x;
}
const ll CRTN=20;
namespace CRT{
ll N;
ll m[CRTN],a[CRTN];
ll Sol(){
ll ans=0,M=1;
for(ll i=1;i<=N;i++) M*=m[i];
for(ll i=1;i<=N;i++){
ll Mi=M/m[i];
ans=(ans+Mi*Inv(Mi,m[i])*a[i])%M;
}
return ans;
}
}
int main(){
using namespace CRT;
scanf("%lld",&N);
for(ll i=1;i<=N;i++)
scanf("%lld%lld",&m[i],&a[i]);
printf("%lld",Sol());
return 0;
}
중국 잉여 정리의 ExCRT 확대
ExCRT와 CRT는 루카스 (함께 할 수 ExLucas 아무것도으로, 중요하지 않습니다
사실, 순수 추론의 관점에서, ExCRT은 (조금 그리워 할 수 있습니다
유도
브라운관 문제지만, 계수는 임의이며 서로 소가 필요하지 않습니다.
이 때, 우리는 역 요소의 존재를 보장 할 수 없습니다. 어떻게이 문제를 해결하기 위해?
두 방정식을 병합하는 방법을 고려한다. 우리는 병합 할 수있는 방법을 찾을 수 있다면, 우리는 동일 할 수있을 것입니다 \ (n \) 에 대한 답변을 얻을, 합병 차례로 방정식을.
\ [\ 좌 \ {을 시작 \
{} 배향 X 및 \ 당량 A_1 \ pmod에 m_1과 {} \\ X 및 \ 당량 A_2 \ pmod에 m_2 {} \ {단부 정렬} \ 권리. \] 불확실성으로 제거됨 congruences 방정식
\ [\ 좌측 \ {을 시작 \ {} 배향 및 X = + A_1 y_1 m_1와, X = \\ m_2 y_2 + A_2 \ 단부 {} 배향 \ 권리. \]
이에 수득
\ [y_1 m_1과 m_2 = + A_1 y_2 + A_2 \]
그냥 스타일을 만날 수있는 그룹을 찾을 \ (y_1 \) 와 \ (y_2 \) , 역 계산 될 수있다 \ (X 축을 \) 합병을 달성하기 위해.
그리고 우리가 얻을 바이너리 방정식의 하나입니다, 당신은 exgcd 해결 사용할 수 있습니다.
표준 타입으로
\ [m_1과 y_1 - m_2 y_2 = A_2 - A_1 \]
솔루션은 원한다. 솔루션이 없을 경우 일치하는 식을 나타내는 아무런 해결책이 없다.
최종적 화학식 결합 얻어진
\ [X \ 당량 m_1과 y_1 + A_1 \ {pmod에 LCM (m_1과, m_2)} \]
실현
단주의해야 할 점은이 솔루션은 방정식을 해결 되었어야한다는 것입니다 \ ((m_1과는 -m_2, A_2-A_1) \) 하지만, 하드 ExGCD가 있으므로, 음수를 다루는 \ (m_2 \) 에 \ (m_1와 \) . 우리가 사용하지 않기 때문에 \ (y_2을 \) , 분명히 거기에 영향을받지 않습니다.
보드 질문 : 익스프레스 정수에 poj2891 이상한 방법 또는 루오 구 P4777, 중국 잉여 정리를 확장 (EXCRT)
잡은 곱셈 버스트 LL 받기변경 너무 게으른
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<vector>
#include<map>
#include<set>
using namespace std;
typedef long long ll;
namespace ExGcd{
ll x,y;
ll ExGcd(ll a,ll b){
ll ans;
if(a%b==0){
x=0;y=1;ans=b;
}else{
ans=ExGcd(b,a%b);
ll x1=x,y1=y;
x=y1;y=x1-a/b*y1;
}
return ans;
}
bool SolveEqu(ll a,ll b,ll c){
ll d=ExGcd(a,b);
if(c%d!=0) return 0;
x*=c/d;y*=c/d;
x=(x%b+b)%b;
y=(c-a*x)/b;
return 1;
}
}
ll Gcd(ll a,ll b){
if(a%b==0) return b;
return Gcd(b,a%b);
}
namespace ExCRT{
ll a1,m1;
void Init(){
a1=0;m1=1;
}
void Expand(ll a2,ll m2){
ExGcd::SolveEqu(m1,m2,a2-a1);
ll y1=ExGcd::x;
ll mn=m1*m2/Gcd(m1,m2);
a1=(m1*y1+a1)%mn;
m1=mn;
}
}
int main(){
ll N;scanf("%lld",&N);
ExCRT::Init();
for(ll i=1;i<=N;i++){
ll a,m;scanf("%lld%lld",&m,&a);
ExCRT::Expand(a,m);
}
printf("%lld",ExCRT::a1);
return 0;
}