poj 2891 Strange Way to Express Integers (求解线性同余方程组/模板)
题意:给你n个对数,ai,ki
X = a1 *x1 + k1
X = a2 *x2 + k2
.....
X = ai*xi + ki
问你是否存在这样一个X,存在就输出该值,否则输出-1
思路:
对于模线性方程组,可以进行方程组合并,求出合并后的方程的解,这样就可以很快的推出方程的最终解,不管这样的方程有多少个,都可以俩俩解决,求得方程组的最终解。
x=b1(mod m1) (1);
x=b2(mod m2) (2);
令m=lcm(m1,m2).
首先,此次方程组有解的充分必要条件是gcd(m1,m2)|gcd(b1,b2),此时方程仅有一个小于m 的非负整数解,利用扩展欧几里德算法解出来。
式(1)等价于x=b1+m1*y1;
式(2)等价于x=b2+m2*y2;
联立可得b1+m2*y1=b2+m2*y2,即m2*y2-m1*y1=b1-b2;
根据之前所学模线性方程的方法,很容易得到此方程的解有y2,因此小于m的非负整数解即为(b2+m2*y2)%m。
明显这是其中一组解,y2+K*lcm(m1,m2)都是解(每次加上最小公倍数)。(k=0,1,2,3。。。)
代码:
#include <iostream> #include <cstdio> #define ll long long using namespace std; ll exgcd(ll a,ll b,ll &x,ll &y) { if(b==0) { x=1; y=0; return a; } ll d=exgcd(b,a%b,x,y); ll t=x; x=y; y=t-a/b*y; return d; } ll solve(ll a[],ll r[],ll n) { ll d,c,i,x,y,t; for(i=1;i<n;i++) { c=r[i]-r[i-1]; d=exgcd(a[i-1],a[i],x,y); if(c%d!=0) return -1; t=a[i]/d; x=(x*(c/d)%t+t)%t; r[i]=a[i-1]*x+r[i-1]; a[i]=a[i-1]*(a[i]/d); } return r[n-1]; } int main() { ll n; ll a[100005]; ll r[100005]; while(cin>>n) { for(int i=0;i<n;i++) scanf("%lld %lld",&a[i],&r[i]); ll ans=solve(a,r,n); cout<<ans<<endl; } return 0; }