Wwwwww 블로그에 대한 파렴치한 선전
기사 목록 - 핵융합 원자로 노심 - 루오 Gubo 오프
합동 해결 식 (확장, 중국 잉여 정리)
P4777 [템플릿] 중국 잉여 정리를 확장 (EXCRT)
다음 합동 식을 해결하려면
\ (\ 시작 {경우} X \ 당량 A_1 \ pmod에 {B_1} \\ X \ 당량 A_2 \ pmod에 {B_2} \\ ...... \\ X \ 당량 a_n \ pmod에 {b_n} \\\ 끝 {경우} \)
상기 식에서, \ (A_I, B_i \) 음이 아닌 정수, \ (B_1은 B_2는, ..., B_n는 \) 반드시 서로 소
해결 :
전과 수득되었다고 \ (K-1 \) 방정식의 해법 \ (X_ {K-1}은
\) 배치 \ (M = I = {LCM_한다. 1. 1} ^ {K} -bI \) , 즉 \ (M은 \) 전면에 인 \ (K-1 \) 모듈러스 (\ B의 \) 최소 공배수그러면 :
제 들어 \ (K-1 \) 식을 만족 \ (X_ {K-1}
+ tM으로 \ 당량 A_I \ pmod에 {b_i} \ \ Z IN (t의 \) \) 즉 : 전 \ (K -1 \) 방정식의 일반 해 \ (X_ {K-1} + tM으로 \ \에서 Z (t의 \) \)제 얻었다 소망 \ (K \) 제 방정식의 해법, 얻어진 용액을 또한 충족 \가 (K-1 \) 방정식
그것은 :
제하는 것이 필요하다 \ (K \) 식 중의, 전 \ (K-1 \) 방정식의 해법을 전달하는 것은 또한 제 만족하면서 \을 (K \) 식의 조건.다만, 제 1 \ (K \) 방정식의 해법 \ (x_k X_ = K- { 1} + tM으로 \ \에서 Z (t의 \) \)
처음에이 용액을 대입 (K \) \ 방정식을 얻을 수있다 :
(\. X_ {K} 1-TM + \ 당량 a_k \ PMOD b_k} {\)
즉 : \ (TM \ - K-당량 a_k-X_ { 1} \ {pmod에 b_k} \
) 여기서 . \ (M, a_k, K-1} {X_ \ b_k)가 알려져있다.사용 \ (exgcd의 \)은 이 합동 식을 얻을 수 해결 \ (T \) 값.
\ (T \) 값은 다시 치환 \ (K-x_k X_ {} = tM으로 +. 1 \ \ (T \)가 Z에 \) 를 얻을 수있다 \ (\ x_k) 값
들면 \ (K \) 의 동작 시간 후, 방정식의 해를 얻을 수있다.
이 질문에 구덩이 :
데이터 범위 :
만약 당신이 열어 \ (긴 \ 오래 \) , 나는 어쨌든 날려받을 때
변수를 폭파 방지하기 위해이라는 기술을 사용하여 빠른 곱셈 모듈로 홀수 \ ((바) \) 멋진 \ ((카) \) 알고리즘을.
신속한 승산 모듈
(또한 거북 속도 배율로 알려짐)그것의 본질과 유사한 이상 걸릴 수있는 신속하게 전력, 이진 분할 응용 프로그램입니다.
가정 \ (K \) \ (A \) 승산
고속의 분해에 의해 \ (a \ 시간의 2A \ 배 4A \ 시간 .... \) 형태.
이것은 가장자리 측 붕괴 변수, 데이터 오버 플로우를 방지하기 위해 나머지을 취할 수있다.그러나 시프트 승산 시간 복잡도는
급격히 끌어 \ (O (logn) \) 레벨ll mul(ll A,ll B,ll mod) //快速乘取余 模板 { ll ans=0; while(B>0) { if(B & 1) ans=(ans+A%mod)%mod; A=(A+A)%mod; B>>=1; } return ans; }
코드에서 :
#include<cstdio>
using namespace std;
typedef long long ll;
ll n;
ll a[100010],b[100010];
ll mul(ll A,ll B,ll mod) //快速乘取余 模板
{
ll ans=0;
while(B>0)
{
if(B & 1) ans=(ans+A%mod)%mod;
A=(A+A)%mod;
B>>=1;
}
return ans;
}
ll exgcd(ll A,ll B,ll &x,ll &y) //扩展欧几里得 模板
{
if(!B)
{
x=1,y=0;
return A;
}
ll d=exgcd(B,A%B,x,y);
ll tmp=x;
x=y , y=tmp-A/B*y;
return d;
}
ll lcm(ll A,ll B) //求最小公倍数
{
ll xxx,yyy;
ll g=exgcd(A,B,xxx,yyy);
return (A/g*B);
}
ll excrt() //重点:求解同余方程组
{
ll x,y;
ll M=b[1],ans=a[1]; //赋初值
//M为前k-1个数的最小公倍数,ans为前k-1个方程的通解
for(int i=2;i<=n;i++)
{
ll A=M,B=b[i];
ll C=(a[i]-ans%B+B)%B; //代表同余方程 ax≡c(mod b) 中a,b,c
ll g=exgcd(A,B,x,y);
//求得A,B的最大公约数,与同余方程ax≡gcd(a,b)(mod b)的解,
if(C%g) return -1; //无解的情况
x=mul(x,C/g,B); //求得x的值,x即t
ans+=x*M; //获得前k个方程的通解
M=lcm(M,B); //更改M的值
ans=(ans%M+M)%M;
}
return ans;
}
int main()
{
scanf("%lld",&n);
for(int i=1;i<=n;i++)
scanf("%lld%lld",&b[i],&a[i]);
ll ans=excrt();
printf("%lld",ans);
}