zoukankan      html  css  js  c++  java
  • 【luogu P4777】【模板】扩展中国剩余定理(EXCRT)(数论)

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

    题目链接:luogu P4777

    题目大意

    给你一些条件,要你找最小的 x,使得满足它被一些数取模的答案是要求的数。
    模数不一定互质。
    在这里插入图片描述

    思路

    不会 CRT 的自己先看看 CRT 怎么写。(点我查看)

    不难想到,前面我们是将式子的答案选可以加载一起的直接加在一起。
    但你不难想到你搞逆元的时候可能会没有逆元,因为模数与你要逆元的数可能并不互质。

    那要怎么搞呢?我们重新考虑如何合并两条式子:
    (xequiv c_1(mod m_1))
    (xequiv c_2(mod m_2))
    那首先很显然的是我们设 (M= ext{lcm}(m_1,m_2)),如果有解,那一定是合并成这样:
    (xequiv c_3(mod M))
    那我们继续设 (t=gcd(m_1,m_2)),那根据我们可以得到这两个式子:
    (c_3=c_1+a imes m_1(0leqslant a< M/m_1))
    (c_3=c_2+b imes m_2(0leqslant b< M/m_2))
    (后面 (a) 的范围后面的限制 (M/m_1) 也可以写成 (m_2/t)
    (b) 也同理)

    那接着两个式子相等:
    (c_1+a imes m_1=c_2+b imes m_2)
    (c_2-c_1=a imes m_1-b imes m_2)
    因为 (t=gcd(m_1,m_2)) 所以 (a imes m_1-b imes m_2) 只能表示 (t) 的倍数。((a,b) 是你要求的)
    所以有解的条件就是 (t|(c_2-c_1))

    那接着你想,你要把 (a,b) 其中一个消掉,就可以求另一个了。
    那要怎么消呢?用取模。
    你会发现前面有一个 (a<M/m_1),而且它也可以写成 (m_2/t)
    那你发现你把前面的式子都除以 (t)
    ((c_2-c_1)/t=a imes m_1/t-b imes m_2/t)
    然后再对 (m_2/t) 取模,就有了 ((c_2-c_1)/tequiv a imes m_1/t(mod (m_2/t)))
    那就只剩 (a) 了,我们搞一下,就有了:
    (a= ext{inv}(m_1/t,m_2/t) imes(c_2-c_1)/tmod(m_2/t))

    然后把 (a) 带入回 (c_3=c_1+a imes m_1) 就可以了。

    然后由于数据规模是 (10^{18}),用乘法都会爆炸,那我们就用黑科技并不龟速的龟速乘。
    然后不开 long long 见祖宗——我 是 傻 逼。

    代码

    #include<cstdio>
    #define ll long long
    
    using namespace std;
    
    int n;
    ll a[100001], b[100001];
    
    ll ksc(ll x, ll y, ll mo) {
    	x %= mo;
    	y %= mo;
    	ll c = (long double)x * y / mo;
    	long double re = x * y - c * mo;
    	if (re < 0) re += mo;
    		else if (re >= mo) re -= mo;
    	return re;
    }
    
    ll gcd(ll x, ll y) {
    	if (!y) return x;
    	return gcd(y, x % y);
    }
    
    ll exgcd(ll a, ll b, ll &x, ll &y) {
    	if (!b) {
    		x = 1;
    		y = 0;
    		return a;
    	}
    	ll re = exgcd(b, a % b, y, x);
    	y -= (a / b) * x;
    	return re;
    }
    
    ll inv(ll a, ll mo) {
    	ll x, y;
    	exgcd(a, mo, x, y);
    	x = (x % mo + mo) % mo;
    	return x;
    }
    
    int main() {
    //	freopen("read.txt", "r", stdin);
    	
    	scanf("%d", &n);
    	for (int i = 1; i <= n; i++) scanf("%lld %lld", &a[i], &b[i]);
    	
    	for (int i = 2; i <= n; i++) {
    		ll t = gcd(a[1], a[i]);
    		ll M = a[i] / t * a[1];
    		ll A = ksc(inv(a[1] / t, a[i] / t), (b[i] - b[1]) / t, a[i] / t);
    		b[1] = ((b[1] + ksc(A, a[1], M)) % M + M) % M;
    		a[1] = M;
    	}
    	
    	printf("%lld", b[1]);
    	
    	return 0;
    }
    
  • 相关阅读:
    UVa 116 单向TSP(多段图最短路)
    POJ 1328 Radar Installation(贪心)
    POJ 1260 Pearls
    POJ 1836 Alignment
    POJ 3267 The Cow Lexicon
    UVa 1620 懒惰的苏珊(逆序数)
    POJ 1018 Communication System(DP)
    UVa 1347 旅行
    UVa 437 巴比伦塔
    UVa 1025 城市里的间谍
  • 原文地址:https://www.cnblogs.com/Sakura-TJH/p/luogu_P4777.html
Copyright © 2011-2022 走看看