exCRT & 骆克强乘法

exCRT & 骆克强乘法

只是丢两个板子啦。

exCRT的做法就是每次拿两个方程合并成一个,合并的过程推下式子就是个 exgcd。具体可以在 zjk 的 ptt 里面找到。

先放个 $ O(1) $ 慢速乘

ll mul( ll a , ll b , ll p ) { a %= p , b %= p; return ( (a * b - (ll)( (ll)( (long double)a / p * b + 0.5 ) * p )) % p + p ) % p; }

然后一个 exgcd

void exgcd( ll a , ll b , ll& d , ll& x , ll& y ) {
    if( !b ) { d = a , x = 1 , y = 0; return; }
    else exgcd( b , a % b , d , y , x ) , y -= x * ( a / b );
}

最后是 excrt

Luogu 板子题和 PTT 上的 ab 居然是反着的。。。毒瘤

#include "iostream"
#include "algorithm"
#include "cstring"
#include "cstdio"
using namespace std;
#define MAXN 100006
typedef long long ll;
ll mul( ll a , ll b , ll p ) { a %= p , b %= p; return ( (a * b - (ll)( (ll)( (long double)a / p * b + 0.5 ) * p )) % p + p ) % p; }
int n;
ll A[MAXN] , B[MAXN];
ll gcd( int a , int b ) { return b ? a : gcd( b , a % b ); }
void exgcd( ll a , ll b , ll& d , ll& x , ll& y ) {
    if( !b ) { d = a , x = 1 , y = 0; return; }
    else exgcd( b , a % b , d , y , x ) , y -= x * ( a / b );
}
bool crt( ll& a1 , ll a2 , ll& b1 , ll b2 ) {
    ll d = a2 - a1;
    ll g , k1 , k2;
    exgcd( b1 , b2 , g , k1 , k2 );
    if( d % g ) return 0;
    else {
        ll r = b2 / g;
        k1 = mul( k1 , d / g , r );
        a1 = k1 * b1 + a1;
        b1 = ( b1 * r );
        return 1;
    }
}
ll excrt(  ) {
    ll a1 = A[0] , b1 = B[0] , a2 , b2;
    for( int i = 1 ; i < n ; ++ i ) {
        a2 = A[i] , b2 = B[i];
        if( !crt( a1 , a2 , b1 , b2 ) ) return -1;
    }
    return a1;
}


int main() {
    cin >> n;
    for( int i = 0 ; i < n ; ++ i ) scanf("%lld%lld",&B[i],&A[i]);
    cout << excrt( ) << endl;
}

posted @ 2020-02-25 12:02  yijan  阅读(171)  评论(0编辑  收藏  举报