算法学习之模线性同余方程组(中国剩余定理+求解同余方程组) poj1006+hdu3579
2017-08-23 13:10
323 查看
中国剩余定理
中国剩余定理原文:有物不知其数,三三数之剩二,五五数之剩三,七七数之剩二。问物几何?解法:中国剩余定理描述的就是一元线性同余方程组(其中m1,m2,...,mn均互质)。
设
是整数m1,m2, ... ,mn的乘积,并设Mi是除了mi以外的n- 1个整数的乘积。
设
为Mi模mi的逆元,所以有
将(S)的通解形式为
(这个式子想了半天才明白是怎么来的:依次模m1,m2,...,mn,就形成了(S)方程组了,因为有下列两个方程)
①
②
在模M意义下,(S)有唯一解
(以上来自百度百科)
poj1006
题意:人生来就有三个生理周期,分别为体力、感情和智力周期,它们的周期长度为23天、28天和33天。每一个周期中有一天是高峰。现在给出三个日期对应于该天是体力、感情和智力的高峰。现在给你一个日期,求从这一天起过多少天三个高峰同时出现。
题解:中国剩余定理的运用,23,28和33两两互质。
代码(作为模板,复杂度O(n)):
#include<set> #include<map> #include<stack> #include<queue> #include<vector> #include<string> #include<bitset> #include<algorithm> #include<cstring> #include<cstdio> #include<cmath> #include<ctime> #include<iomanip> #include<iostream> #define debug cout<<"aaa"<<endl #define d(a) cout<<a<<endl #define mem(a,b) memset(a,b,sizeof(a)) #define LL long long #define lson l,mid,root<<1 #define rson mid+1,r,root<<1|1 #define MIN_INT (-2147483647-1) #define MAX_INT 2147483647 #define MAX_LL 9223372036854775807i64 #define MIN_LL (-9223372036854775807i64-1) using namespace std; const int N = 3 + 5; const int mod = 1000000000 + 7; const double eps = 1e-8; //扩展欧几里德 LL exgcd(LL a,LL b,LL &x,LL &y){ if(b==0){ x=1; y=0; return a; } LL r=exgcd(b,a%b,x,y); LL t=x; x=y; y=t-a/b*y; return r; } //中国剩余定理 r[]存放余数 a[]存放两两互质的除数 LL CRT(LL a[],LL w[],int n){ LL M=1,ans=0; for(int i=1;i<=n;i++){ M*=w[i]; } for(int i=1;i<=n;i++){ LL x,y,temp; temp=M/w[i]; exgcd(w[i],temp,x,y);//求逆元 ans=(ans+a[i]*temp*y)%M; } return (ans%M+M)%M; } LL a ,r ; int main(){ int cas=0; LL p,e,i,d,ans; const LL temp=21252;//23,28,33的lcm while(scanf("%lld%lld%lld%lld",&p,&e,&i,&d)){ if(p==-1&&e==-1&&i==-1&&d==-1){ break; } a[1]=p,a[2]=e,a[3]=i; r[1]=23,r[2]=28,r[3]=33; ans=CRT(a,r,3); while(ans<=d){ ans+=temp; } printf("Case %d: the next triple peak occurs in %lld days.\n",++cas,ans-d); } return 0; }
求解同余方程组
中国剩余定理就是在求解同余方程组,但是当除数两两不互质的情况。就不能用CRT的结论来解决。还是这个方程组,现在取出其中两个方程:
x≡a1(mod m1)
x≡a2(mod m2)
转化为:
x+m1*x1=a1
x+m2*x2=a2
合并有:m1*x1+m2*x2=a1-a2
可以通过扩展欧几里德解出,若(a1-a2)%gcd(m1,m2)!=0,则无解
反之解出x1,带入x+m1*x1=a1,得到一个特解x0=a1-m1*x1。
通解x=x0+k*lcm(a1,a2),即x≡x0(mod lcm(a1,a2)。
这样一来两个方程就合并成一个了,将这n个方程全部合并就可以解出x了。
hdu3579
题意:同中国剩余定理原文(这里除数两两不互质)
代码(作为模板,复杂度O(n)):
#include<set> #include<map> #include<stack> #include<queue> #include<vector> #include<string> #include<bitset> #include<algorithm> #include<cstring> #include<cstdio> #include<cmath> #include<ctime> #include<iomanip> #include<iostream> #define debug cout<<"aaa"<<endl #define d(a) cout<<a<<endl #define mem(a,b) memset(a,b,sizeof(a)) #define LL long long #define lson l,mid,root<<1 #define rson mid+1,r,root<<1|1 #define MIN_INT (-2147483647-1) #define MAX_INT 2147483647 #define MAX_LL 9223372036854775807i64 #define MIN_LL (-9223372036854775807i64-1) using namespace std; const int N = 1000000 + 5; const int mod = 1000000000 + 7; const double eps = 1e-8; LL exgcd(LL a,LL b,LL &x,LL &y){ if(b==0){ x=1; y=0; return a; } LL r=exgcd(b,a%b,x,y); LL t=x; x=y; y=t-a/b*y; return r; } //中国剩余定理 r[]存放余数 a[]存放两两互质的除数 /*若模数两两互质,我们可以用中国剩余定理来解。 这里我们先考虑两个方程: x≡a1(mod m1) x≡a2(mod m2) 我们可以写成: x+x1m1=a1 x+x2m2=a2 合并有:m1*x1+m2*x2=a1-a2 可以通过扩展欧几里德解出,若(a1-a2)%gcd(m1,m2)!=0,则无解 反之解出x1,带入x+m1*x1=a1,得到一个特解x0=a1-m1*x1。 通解x=x0+k*lcm(a1,a2),即x≡x0(mod lcm(a1,a2)。 这样一来两个方程就合并成一个了,将这n个方程全部合并就可以解出x了。 */ LL solve(LL a[],LL r[],int n){ LL M=a[1],R=r[1],x,y,d,temp; for(int i=2;i<=n;i++){ d=exgcd(M,a[i],x,y); if((R-r[i])%d!=0) return -1;//无解 temp=a[i]/d; x=(R-r[i])/d*x;//特解x1。 x=(x%temp+temp)%temp; R-=x*M;//更新余数。 M=M*temp;////更新模数(M是lcm(a[i],M))。 R%=M; } return R==0?M:(R%M+M)%M;//余数全为0,则返回lcm } LL a ,r ; int main(){ int n,t,cas=0; scanf("%d",&t); while(t--){ scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%lld",&a[i]); } for(int i=1;i<=n;i++){ scanf("%lld",&r[i]); } printf("Case %d: %lld\n",++cas,solve(a,r,n)); } return 0; }
留个模板
写的可能不太清楚嘿~
相关文章推荐
- 利用中国剩余定理加速解密算法求解
- POJ1006生理周期----【模板】CRT中国剩余定理即孙子定理即求解一次同余方程
- 算法学习(五)求解500万以内的亲和数,连续数据映射为数组
- 算法设计和数据结构学习_4(《数据结构和问题求解》part4笔记)
- 算法学习:子集和数问题求解
- SVM-支持向量机学习(7):求解SVM算法-SMO-序列最小最优化
- 算法设计和数据结构学习_3(《数据结构和问题求解》part2笔记)
- 学习凸包(一):暴力算法求解
- 算法学习---关于哈密顿图的哈密顿通路求解问题
- 学习匈牙利算法总结(求解二分图最大匹配)
- 算法学习之欧几里得算法求解两个整数的最大公因子
- 算法学习—— 逆序对求解
- 算法学习笔记----用主方法求解递归式
- 小白算法学习:求解两个字符串的最长公共子序列
- 算法学习之暴力求解
- 【算法学习】最大子数组问题的分治法求解
- java基础算法学习之完全数的求解
- 算法学习:贪心求部分背包(使用结构体来求解)
- 线性和并行求解多个序列最长公共子序列(MLCS)算法学习笔记
- 算法学习之二——用DP和备忘录算法求解最长公共子序列问题