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;
    }
    
  • 相关阅读:
    jQuery动态加载动画spin.js
    jQuery自动过滤单词插件
    基于jQuery的自定义滚动条
    jQuery纵向分类下拉菜单导航
    仿酷狗官网新闻焦点图插件
    metro扁平UI网页组件
    HTML5环形音乐播放器
    纯CSS3个性化圆形按钮登录表单
    纯CSS3绘制的黑色图标按钮组合
    纯CSS3实现iOS7扁平化图标
  • 原文地址:https://www.cnblogs.com/Sakura-TJH/p/luogu_P4777.html
Copyright © 2011-2022 走看看