中国剩余定理







2道模板题:
[TJOI2009]猜数字

// luogu-judger-enable-o2
#include<bits/stdc++.h>
using namespace std;
#define R register int
#define AC 15
#define db double
#define LL long long

int k; LL M = 1, ans, tmp;
LL m[AC], a[AC], t[AC];

inline int read()
{
    int x = 0;char c = getchar();bool z = false;
    while(c > '9' || c < '0') {if(c == '-') z = true; c = getchar();}
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    if(!z) return x;
    else return -x;
}

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

inline void up(LL &a, LL b) {a = (a + b) % M;}

inline LL ad(LL x, LL have)
{	
    LL rnt = 0;
    while(have)
    {
        if(have & 1) up(rnt, x);
        up(x, x), have >>= 1;
    }
    return rnt;
}
#define int long long
int Mul(int x, int y){
    return (x * y - (int) (((db) x * y + 0.5) / (db) M)* M + M) % M;
}
#undef int

void pre()
{
    k = read();
    for(R i = 1; i <= k; i ++) a[i] = read();
    for(R i = 1; i <= k; i ++) m[i] = read(), M *= m[i];
    for(R i = 1; i <= k; i ++) a[i] = (a[i] % m[i] + m[i]) % m[i];
}

void work()
{
    for(R i = 1; i <= k; i ++)
    {
        exgcd(M / m[i], m[i], t[i], tmp);
        up(ans, Mul(Mul(a[i], M / m[i]), t[i]));		
    }
    printf("%lld\n", (ans % M + M) % M);
}

int main()
{
//	freopen("in.in", "r", stdin);
    pre();
    work();
//	fclose(stdin);
    return 0;
}

【模板】扩展中国剩余定理(EXCRT)

// luogu-judger-enable-o2
#include<bits/stdc++.h>
using namespace std;
#define R register int
#define AC 101000
#define ld long double
#define LL long long

int n;
LL c[AC], m[AC];

inline LL read()//读入开LL
{
    LL x = 0;char c = getchar();
    while(c > '9' || c < '0') c = getchar();
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x;
}

void pre()
{
    n = read();
    for(R i = 1; i <= n; i ++) m[i] = read(), c[i] = read();
}

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

inline LL gcd(LL x, LL y)
{
    for(LL t; y; t = x, x = y, y = t % x);
    return x;
}

LL mul(LL a, LL b, LL p)//O(1)快速乘 
{
    a %= p, b %= p;
    LL t = (ld) a * b / p;
    LL r = a * b - p * t;
    if (r < 0) r += p;
    return r;
}

void EXCRT()
{
    LL C = c[1], M = m[1], inv;
    for(R i = 2; i <= n; i ++)
    {
        LL t = gcd(m[i], M), p = M / t, now = M, k = m[i] / t;
        M = M / t * m[i];//先除再乘防止爆LL
        exgcd(p, m[i] / t, inv, m[0]), inv = (inv % k + k) % k;//求出m1 / t在m2 / t意义下的逆元
        C = (mul(mul((c[i] - C) / t, inv, M), now, M) + C) % M;
        //printf("%lld %lld\n", C, M);
    }
    LL ans = (C % M + M) % M;
    printf("%lld\n", ans);
}

int main()
{
//	freopen("in.in", "r", stdin);
    pre();
    EXCRT();
//	fclose(stdin);
    return 0;
}
posted @ 2019-01-31 16:11  ww3113306  阅读(140)  评论(1编辑  收藏  举报
知识共享许可协议
本作品采用知识共享署名-非商业性使用-禁止演绎 3.0 未本地化版本许可协议进行许可。