문제 P4777에 해결 [[템플릿] 중국 잉여 정리를 확장 (EXCRT)]

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

추천

출처www.cnblogs.com/luckyblock/p/11456333.html