POJ2115 C Looooops(数论)

题目链接

分析:

数论了解的还不算太多,解的时候,碰到了不小的麻烦。

 

设答案为x,n = (1<<k), 则 (A+C*x) % n == B

即 (A+C*x) ≡ B (mod n)

化简得 C*x ≡ (B-A) (mod n)

设 a = C, b = (B-A)

则原式变为 ax=b.解 x。

 

到这里,以为求出来 a 的逆, 然后 x = b*a-1

a 的 逆好求,用《训练指南》上的模板(P122) inv函数. 

例如,求 2 模 66536 下的逆, inv(2, 66536) 便可, 但 inv(LL a, LL n) 这个函数的要求就是如果 a 和 n 的最大公约数不为1,则逆不存在。 但样例是有解的。

在网上查了一下,说是《算法导论》(第三版)P555页有解法, 便根据书上的解法解 x 了。

 

代码如下:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <algorithm>
#include <cmath>
#include <string>
#include <map>
#include <set>

using namespace std;

typedef long long LL;

void gcd(LL a, LL b, LL &d, LL &x, LL &y) {
    if(!b) { d = a; x = 1; y = 0; }
    else { gcd(b, a%b, d, y, x); y-= x*(a/b); }
}

int main() {
    LL A, B, C, k, n, x, y, d;

    while(cin >> A >> B >> C >> k) {
        if(A == 0 && B == 0 && C == 0 && k == 0) break;

        n = (1LL << k);

        LL a = C;
        LL b = (B-A+n)%n;

        if(b == 0) { printf("0\n"); continue; }

        gcd(a, n, d, x, y);

        if(b % d == 0) {
            LL x0 = (x*(b/d)) % n;
            LL minn = (x0%(n/d)+n/d)%(n/d);
            cout << minn << endl;
        }
        else printf("FOREVER\n");
    }

    return 0;
}

 

 

posted on 2013-07-06 15:37  Still_Raining  阅读(745)  评论(0编辑  收藏  举报