zoukankan      html  css  js  c++  java
  • 中国剩余定理

    CRT

    其实 (EX) 很简单,和普通几乎一样,先上普通版只是心理缓冲 为什么普通版还没淘汰啊

    1. 作用:

      解线性同余方程

      即:

      [egin{cases} xequiv a_1quad(mod;m_1)\ xequiv a_2quad(mod;m_2)\ quad dots\ xequiv a_kquad(mod;m_k)\ end{cases} ]

      限定: (m) 之间两两互质。

    2. 方式:

      分别解:

      [egin{cases} xequiv a_1quad(mod;m_1)\ xequiv 0quad(mod;m_2)\ quad dots\ xequiv 0quad(mod;m_k)\ end{cases} egin{cases} xequiv 0quad(mod;m_1)\ xequiv a_2quad(mod;m_2)\ quad dots\ xequiv 0quad(mod;m_k)\ end{cases} egin{cases} xequiv 0quad(mod;m_1)\ xequiv 0quad(mod;m_2)\ quad dots\ xequiv a_kquad(mod;m_k)\ end{cases} ]

      解法:

      (M=prod_{i=1}^k m_i)(M_i=frac{M}{m_i})

      这样就保证了 (M_i) 除了模 (m_i) 以外都为 (0) 。然后我们要解 $M_it_iequiv a_iquad(mod;m_i) $ ,用 (exgcd) 解就行辽。 当然我们可以发现,(t_i)(M_i) 的逆元乘 (a_i) ,如果处理过逆元就不用再解方程了。

      最终答案是 (sum_{i=1}^{k} M_it_i)

      注意,为了满足所有的 (mod;m) 成立,统计答案时必须模 (m)(lcm) ,因为它们互质,所以模 (M) 就行辽。

    3. MOD luogu P3868

      模板题,但是要打快速乘((O(log^n)))。

      如果在一些奇怪的地方看到一些奇怪的快速乘((O(1))) ,最好不要打,(int128) 考试用不了,(long double) 也非常玄学,会锅。

      #include<cstdio>
      #include<algorithm>
      using namespace std;
      typedef int int_;
      #define int long long
      
      
      int n; 
      int m[20],aa[20],bb[20];
      int M=1,ans;
      
      int times(int x,int y,int p){
      	int ret=0,flag=0;
      	if(y<0){
      		y=-y;
      		flag=1;
      	}
      	while(y>0){
      		if(y&1) ret=((ret+x)%p+p)%p;
      		x=((x<<1)%p+p)%p;
      		y>>=1;
      	}
      	if(flag) return (((-ret)%p)+p)%p;
      	else return ((ret%p)+p)%p;
      }
      
      void exgcd(int a,int b,int &x,int &y){
      	if(b==0){
      		x=1,y=0;
      	}
      	else{
      		exgcd(b,a%b,y,x);
      		y-=(a/b)*x;
      	}
      }
      
      int_ main()
      {
      	scanf("%lld",&n);
      	for(int i=1;i<=n;i++){
      		scanf("%lld",&aa[i]);
      	}
      	for(int i=1;i<=n;i++){
      		scanf("%lld",&bb[i]);
      	  	M*=bb[i];
      	}
      	for(int i=1;i<=n;i++){
      		m[i]=M/bb[i];
      		int p,q;
      		exgcd(m[i],bb[i],p,q);
      		p=times(p,aa[i],M);
      		p=((p%M)+M)%M;
      		ans+=times(m[i],p,M);
      		ans%=M;
      	}
      	printf("%lld",ans);
      	return 0;
      }
      
      

    多解问题

    这个标题是之后添加的,在这里

    EX

    普通版 (CRT) 其实有点 (low) ,看看就行辽,重点在 (EXCRT)

    1. 作用

      同上,解线性同余方程组,但是没有 (m) 互质的条件。

      [egin{cases}xequiv a_1quad(mod;m_1)\xequiv a_2quad(mod;m_2)\quad dots\xequiv a_kquad(mod;m_k)\end{cases} ]

    2. 这样我们就要一个一个解:

      对于一个同余方程,设已经解出其前面的方程的通解 (ans) 。那么我们就要解:

      [egin{cases} xequiv ansquad(mod;M)\ xequiv a_iquad(mod;m_i) end{cases} ]

      其中 (M) 是前面方程的 (m)(lcm)

      方程组可以化成:

      [m_ip+a_i= Mq+ansimplies m_ip+M(-q)=ans-a_i ]

      之后用 (exgcd) 解出 (p)(q),那么 (x=m_ip+a_i)(x=Mq+ans)

      可以注意到,当 (m) 两两互质时 (gcd(M,m_i)=1) 即方程一定有解,而 (gcd(M,m_i)) 无法整除 ((ans-a_i)) 时方程无解。

    3. 模板 luogu P4777

      (excrt) 的难点主要在于取模的细节。

      #include<cstdio>
      #include<algorithm>
      using namespace std;
      typedef int int_;
      #define int long long
      
      int n,ans,M,m[100050],aa[100050],bb[100050];
      int times(int x,int y,int p){
      	int ret=0,flag=0;
      	if(y<0){
      		y=-y;
      		flag=1;
      	}
      	while(y>0){
      		if(y&1) ret=(ret+x)%p;
      		x=(x<<1)%p;
      		y>>=1;
      	}
      	if(flag) return (((-ret)%p)+p)%p;
      	else return ((ret%p)+p)%p;
      }
      int gcd(int a,int b){
      	return b==0?a:gcd(b,a%b);
      }
      
      void exgcd(int a,int b,int &x,int &y){
      	if(b==0){
      		x=1,y=0;
      	}
      	else{
      		exgcd(b,a%b,y,x);
      		y-=(a/b)*x;
      	}
      }
      
      int_ main()
      {
      	scanf("%lld",&n);
      	for(int i=1;i<=n;i++){
      		scanf("%lld %lld",&aa[i],&bb[i]);
      	}
      	ans=bb[1],M=aa[1];
      	for(int i=2;i<=n;i++){
      		int g=gcd(aa[i],M);
      		if((ans-bb[i])%g != 0){
      			printf("No Solution");
      			return 0;
      		}
      		int x,y;
      		exgcd(aa[i],M,x,y);
      		x=times(x,(ans-bb[i])/g,M/g);//这里是gcd求最小正整数解,要模另一个系数除gcd
      		M*=aa[i]/g;
      		ans=(times(aa[i],x,M)+bb[i]+M)%M; //为了保证模意义下成立,要模更新过的lcm
      	}
      	printf("%lld",ans);
          return 0;
      }
      

    -EOF-
  • 相关阅读:
    LeetCode: 389 Find the Difference(easy)
    LeetCode: 669 Trim a Binary Search Tree(easy)
    C++: 内联函数
    C++: STL迭代器及迭代器失效问题
    LeetCode: 371 Sum of Two Integers(easy)
    etcdctl命令
    Etcd介绍
    docker基础镜像打包
    docker常见问题总结
    更改容器内时区
  • 原文地址:https://www.cnblogs.com/thornblog/p/11890895.html
Copyright © 2011-2022 走看看