hihocoder 1303 : 數論六·模線性方程組
阿新 • • 發佈:2019-02-11
hihocoder 1303
描述
小Ho:今天我聽到一個挺有意思的故事!
小Hi:什麼故事啊?
小Ho:說秦末,劉邦的將軍韓信帶領1500名士兵經歷了一場戰鬥,戰死四百餘人。韓信為了清點人數讓士兵站成三人一排,多出來兩人;站成五人一排,多出來四人;站成七人一排,多出來六人。韓信立刻就知道了剩餘人數為1049人。
小Hi:韓信點兵嘛,這個故事很有名的。
小Ho:我覺得這裡面一定有什麼巧妙的計算方法!不然韓信不可能這麼快計算出來。
小Hi:那我們不妨將這個故事的數學模型提取出來看看?
小Ho:好!
<小Ho稍微思考了一下>
小Ho:韓信是為了計算的是士兵的人數,那麼我們設這個人數為x。三人成排,五人成排,七人成排,即x mod 3, x mod 5, x mod 7。也就是說我們可以列出一組方程:
x mod 3 = 2
x mod 5 = 4
x mod 7 = 6
韓信就是根據這個方程組,解出了x的值。
小Hi:嗯,就是這樣!我們將這個方程組推廣到一般形式:給定了n組除數m[i]和餘數r[i],通過這n組(m[i],r[i])求解一個x,使得x mod m[i] = r[i]。
小Ho:我怎麼感覺這個方程組有固定的解法?
小Hi:這個方程組被稱為模線性方程組。它確實有固定的解決方法。不過在我告訴你解法之前,你不如先自己想想怎麼求解如何?
小Ho:好啊,讓我先試試啊!
輸入
第1行:1個正整數, N,2≤N≤1,000。
第2..N+1行:2個正整數, 第i+1行表示第i組m,r,2≤m≤20,000,000,0≤r<m。
計算過程中儘量使用64位整型。
輸出
第1行:1個整數,表示滿足要求的最小X,若無解輸出-1。答案範圍在64位整型內。
樣例輸入
- 3
- 3 2
- 5 3
- 7 2
樣例輸出
- 23
Solution
中國剩餘定理,注意解不定方程組的一些細節
Code
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <cmath> #include <stack> #include <map> #include <vector> #include <queue> #define LL long long #define L 1010 using namespace std; int n, m[L], r[L]; LL M, R; inline LL gcd(LL x, LL y) { return (x % y == 0) ? y : gcd(y, x % y); } inline void exgcd(LL a, LL b, LL& x, LL& y) { if (!b) {x = 1, y = 0;} else { exgcd(b, a % b, y, x); y -= (a / b) * x; } } inline LL solve() { M = m[1], R = r[1]; for (int i = 2; i <= n; ++i) { LL d = gcd(M, m[i]), c = r[i] - R; if (c % d) return -1; LL x, y; exgcd(M / d, m[i] / d, x, y); x = (c / d * x) % (m[i] / d); R += x * M; M = M / d * m[i]; R %= M; } if (R < 0) R += M; return R; } int main() { scanf("%d", &n); for (int i = 1; i <= n; ++i) scanf("%d %d", &m[i], &r[i]); printf("%lld\n", solve()); return 0; }
Summary
注意需要判斷無解的情況,所以不能一味的用通解