zoukankan      html  css  js  c++  java
  • 【洛谷P4777】扩展中国剩余定理(EXCRT)

    题目

    题目链接:https://www.luogu.com.cn/problem/P4777
    给定 \(n\) 组非负整数 \(a_i, b_i\) ,求解关于 \(x\) 的方程组的最小非负整数解。

    \[\begin{cases} x \equiv b_1\ ({\rm mod}\ a_1) \\ x\equiv b_2\ ({\rm mod}\ a_2) \\ ... \\ x \equiv b_n\ ({\rm mod}\ a_n)\end{cases} \]

    思路

    \(Excrt\)模板。顺便A了crt模板
    假设我们已经求出了前\(i-1\)个方程的解\(x\),设\(M=\text{LCM}^{i-1}_{j=1}\ p[j]\),那么显然我们需要找到一个数\(t\)满足\(x+tM\equiv a_i(\rm mod\ p_i)\),也就是说\(x+tM=a_i-y·p_i\)
    移项得\(t·M+y·p_i=a_i-x\),其中\(M,x,a_i,p_i\)都是已知项。
    那么就可以用\(Exgcd\)求出\(t\)\(y\)\(d=gcd(M,p_i)\)。由于数据保证有解,那么一定有\(d|(a_i-x)\),所以让\(x=x\times \frac{((a_i-x)\rm mod\ p+p)\rm mod\ p}{d}\)即可。注意这一步可能会超出\(\rm long\ \rm long\)范围,所以用龟速乘即可。
    那么前\(i\)个同余方程组的解即为\(x+tM\)
    然后更新\(x,M\)即可。
    总的来说就是做\(n-1\)\(Exgcd\)

    代码

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    
    const int N=100010;
    ll ans,M,a,p;
    int n;
    
    ll qmul(ll a,ll b,ll MOD)
    {
    	ll ans=0;
    	for (;b;b>>=1,a=(a+a)%MOD)
    		if (b&1) ans=(ans+a)%MOD;
    	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 temp=x; x=y; y=temp-y*(a/b);
    	return d;
    }
    
    void excrt()
    {
    	ll x=0,y=0;
    	ll Gcd=exgcd(M,p,x,y);
    	x=qmul(x,((a-ans)%p+p)%p/Gcd,p);
    	ans+=x*M;
    	M*=p/Gcd;
    	ans=(ans%M+M)%M;
    }
    
    int main()
    {
    	scanf("%d",&n);
    	for (int i=1;i<=n;i++)
    	{
    		scanf("%lld%lld",&p,&a);
    		if (i==1) M=p,ans=a;
    			else excrt();
    	}
    	printf("%lld",ans);
    	return 0;
    }
    
  • 相关阅读:
    HRBUST 1377 金明的预算方案
    51Nod 2649 完全背包
    计蒜客 T2129 采药
    计蒜客 T1408 矩形嵌套
    OpenJudge 2711 合唱队形
    51Nod 2080 最长上升子序列
    2021NUAA暑假集训 Day5 部分题解
    2021NUAA暑假集训 Day4 部分题解
    C++ 11 move constructor 何时调用?
    老外这样说英文
  • 原文地址:https://www.cnblogs.com/stoorz/p/12230455.html
Copyright © 2011-2022 走看看