【模線性方程】POJ 2115
阿新 • • 發佈:2019-02-03
原文地址,感謝大神。
題意:轉化成c * x = b - a mod (2 ^ k),解這個模線性方程的最小正整數解即可
Sample Input
3 3 2 16
3 7 2 16
7 3 2 16
3 4 2 16
0 0 0 0
Sample Output
0
2
32766
FOREVER
解方程:ax == b (mod n);【ax % n == b % n】
設線性模方程的一個解為x0
條件①:有d = gcd(a, n)
條件②:有d = ax1 + ny, 由擴充套件歐幾里得(Egcd)得到x1的值
條件③:b % d == 0 (有解的條件)
對條件③進行解釋:
原方程化為:ax + kn = b (設k為某一整數)
那麼如果a與n的最大公約數為d,那麼ax + kn 必然可以提取一個d的因子,也就是說b必然有d這個因子,所以如果b%d!=0,說明b沒有d這因子,與前面的結論相互矛盾,所以無解
則x0 = x1*(b/d);
證明:
因為:容易求得d = gcd (a, n), 則存在一個x1、y使得d = ax1 + ny①(擴充套件歐幾里得定理,這個都不會的話,說明你數論還沒入門)
方程①2邊同時模n得:d % n == ax1 % n②
又因為:b % d == 0, 即b是d的倍數;
所以(b/d)必為整數;
所以由②得: b % n == d*(b/d) % n == ax1*(b/d) % n == ax % n
所以很容易可以看出x = x1*(b/d)是方程的一個整數解,得證
參考文獻:
#include <iostream> #include <algorithm> #include <string> //#include <map> #include <queue> #include <vector> #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> //#include <ctime> #include <ctype.h> using namespace std; #define LL long long #define inf 0x3fffffff LL Egcd (LL a, LL b, LL &x, LL &y) //擴充套件歐幾里得 { if (b == 0) { x = 1, y = 0; return a; } LL d = Egcd (b, a%b, x, y); LL tp = x; x = y; y = tp - a/b*y; return d; } void MLE (LL a, LL b, LL n) //解模線性方程 { LL d, x, y; d = Egcd (a, n, x, y); if (b % d) { puts ("FOREVER"); return ; } LL x0 = x * (b/d); LL t = n / d; if (t < 0) t = -t; //以防萬一,有的題目t有可能是負數 x0 = (x0 % t + t) % t; //防止負數出現,所以先模後加再模,再模是因為如果是正數,+n/d可能會超出n/d //對於無數個解形成的一群餘數:週期個數是d,週期長度是n/d,也就是最小正整數解在n/d裡,這個聽老師說過,但是忘了為什麼,涉及到群的概念…… printf ("%lld\n", x0); } int main() { LL a, b, c, k; while (scanf ("%lld%lld%lld%lld", &a, &b, &c, &k), (a||b||c||k)) MLE (c, b-a, 1LL<<k); return 0; }