模線性方程組-非互質中國剩餘定理 HDU3579 HDU1573
阿新 • • 發佈:2019-02-20
問題描述:給出bi,ni的值,且n1, n2, n3,…, ni兩兩之間不一定互質,求Res的值?
解:採用的是合併方程的做法。
這裡將以合併第一第二個方程為例進行說明
由上圖前2個方程得(設k1、k2為某一整數):
#include <iostream> using namespace std; #define LL __int64 #define M 10 int N; LL Egcd (LL a, LL b, LL &x, LL &y) { if (b == 0) { x = 1, y = 0; return a; } LL d, tp; d = Egcd (b, a%b, x, y); tp = x; x = y; y = tp - a/b*y; return d; } LL CRT2 (LL b[], LL n[], int num) { int i; bool flag = false; LL n1 = n[0], n2, b1 = b[0], b2, bb, d, t, k, x, y; for (i = 1; i < num; i++) { n2 = n[i], b2 = b[i]; bb = b2 - b1; d = Egcd (n1, n2, x, y); if (bb % d) //模線性解k1時發現無解 { flag = true; break; } k = bb / d * x; //相當於求上面所說的k1【模線性方程】 t = n2 / d; if (t < 0) t = -t; k = (k % t + t) % t; //相當於求上面的K` b1 = b1 + n1*k; n1 = n1 / d * n2; } if (flag) return 0; //無解 /******************求正整數解******************/ if (b1 == 0) //如果解為0,而題目要正整數解,顯然不行 b1 = n1; //n1剛好為所有ni的最小公倍數,就是解了 /******************求正整數解******************/ if (b1 > N) return 0; return (N-b1)/n1+1; //形成的解:b1, b1+n1, b1+2n1,..., b1+xni... } int main() { int t, num, i, cc = 1; LL b[M], n[M]; scanf ("%d", &t); while (t--) { scanf ("%d%d", &N, &num); for (i = 0; i < num; i++) scanf ("%I64d", n+i); for (i = 0; i < num; i++) scanf ("%I64d", b+i); printf ("%I64d\n", CRT2 (b, n, num)); } return 0; }
增加一下HDU3579的程式碼。
#include<iostream> using namespace std; typedef long long int ll; ll a[100],b[100]; ll n,N,x,y; 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 CRT(ll a[],ll b[],ll n){ ll b1=b[0],n1=a[0]; int flag=0; ll k,bb,k1,t,d,b2,n2; for(int i=1;i<n;i++){ b2=b[i]; n2=a[i]; d=exgcd(n1,n2,x,y); bb=b2-b1; if(bb%d){ flag=1; break; } k=bb/d*x; t=n2/d; if(t<0)t=-t; k=(k%t+t)%t; b1=b1+n1*k; n1=n1*t; } if(flag)return -1; if(b1==0)b1=n1;//因為b1如果為0則說明,最小的情況就是隻有一組大小為n的硬幣。 return b1; } int main(){ int t; cin>>t; int n1=1; while(t--){ cin>>n; for(int i=0;i<n;i++)cin>>a[i]; for(int i=0;i<n;i++)cin>>b[i]; cout<<"Case "<<n1++<<": "<<CRT(a,b,n)<<endl; } }