1. 程式人生 > >hdu 2462(數論:尤拉定理+快速冪取模優化+尤拉函式)

hdu 2462(數論:尤拉定理+快速冪取模優化+尤拉函式)

給定一個數,判斷是否存在一個全由8組成的數為這個數的倍數

若存在則輸出這個數的長度,否則輸出0

寫了好久實在想不出來,對著別人的題解才把題目做出來...

通過這個題學會了快速冪,但是程式碼中說的乘法轉化還是看不懂...

百度了一下才知道這個題目是區預賽的題,看來自己和別人還有很多差距啊尷尬

------------------------------------------------------------------------------------------------------------------------------

 首先,由題意可以得出,(10^x - 1)/ 9 * 8 = L * p(p是一個未知數,但必定是整數)。

           然後對上式進行移項處理,得:(10^x - 1) = 9 * L * p / 8。

           設m = 9 * L / gcd(L, 8),則有(10^x - 1) = m * p'。p’是必然存在的一個整數。

           然後問題就轉化成為了 10^x = 1(mod m),觀察此式,顯然,m和10必定互質。

           於是根據尤拉定理,10^(Euler(m)) = 1(mod m) 。由於題目要求最小的解,解必然是Euler(m)的因子。

           需要注意的是,對於10^x,由於m太大,直接快速冪相乘的時候會超long long。。。。好bug,需要乘法轉化一下。

程式碼如下:

#include <vector>
#include <cstdio>
#include <iostream>
#include <algorithm>
#define LL long long
#define MAXN 400010
using namespace std;
bool vis[MAXN];
vector<LL> hav;
vector<int> prime;

LL gcd(LL a, LL b) {
    return b==0 ? a : gcd(b, a%b);
}

void gen_primes() {
    for(int i=2; i<MAXN; ++i) {
        if(!vis[i]) {
            prime.push_back(i);
            if(i < 1111) {
                for(int j=i*i; j<MAXN; j+=i) {
                    vis[j] = true;
                }
            }
        }
    }
    return ;
}

LL euler_phi(LL n) {
    LL ans = n;
    for(int i=0; (LL)(prime[i]*prime[i])<=n; ++i) {
        if(n%prime[i] == 0) {
            ans = ans/prime[i]*(prime[i]-1);
            n /= prime[i];
            while(n%prime[i] == 0)
                n /= prime[i];
        }
    }
    if(n > 1) {
        ans = ans/n*(n-1);
    }
    return ans;
}

LL Mul(LL a, LL b, LL c) {
    LL ans = 0;
    while(b) {
        if(b & 1)
            ans = (ans+a)%c;
        a = a*2%c;
        b >>= 1;
    }
    return ans;
}

LL Pow(LL a, LL b, LL c) {
    LL ans = 1;
    while(b) {
        if(b & 1)
            ans = Mul(ans, a, c);
        a = Mul(a, a, c);
        b >>= 1;
    }
    return ans;
}

void get_hav(LL n) {
    hav.clear();
    for(int i=0; i<prime.size()&&n>1; ++i) {
        while(n%(LL)prime[i] == 0) {
            n /= prime[i];
            hav.push_back(prime[i]);
        }
    }
    if(n > 1)
        hav.push_back(n);
}

int main(void) {
    LL n, m, x, cas = 1;
    gen_primes();
    while(cin >> n && n) {
        m = 9*n/gcd(n, 8LL);
        if(gcd(m, 10LL) != 1) {
            cout << "Case " << cas++ << ": 0" << endl;
            continue;
        }
        x = euler_phi(m);
        get_hav(x);
        for(int i=0; i<hav.size(); ++i) {
            if(Pow(10LL, x/hav[i], m) == 1)
                x /= hav[i];
        }
        cout << "Case " << cas++ << ": " << x << endl;
    }
    return 0;
}