(至少要几个8才能整除给定的数)POJ 3696 The Luckiest number 欧拉函数 或 BSGS

资料来源:https://blog.csdn.net/danliwoo/article/details/48865127

原题见POJ 3696

(不得不说,这哥们的公式是真的6,尝试过手敲之后果断放弃,选择截屏,这大概就是蒟蒻和大佬的差别吧。。) 

BSGS

很快想起了BSGS有木有!上篇博客已经讲过这种算法。

/*--------------------------------------------
 * File Name: POJ 3696
 * Author: Danliwoo
 * Mail: [email protected]
 * Created Time: 2015-10-02 22:16:59
--------------------------------------------*/

#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
#include <algorithm>
#include <cmath>
using namespace std;
#define N 44725
#define LL long long
#define MOD 150000   //是sqrt(1999999999*9)要求那么大的
LL gcd(LL a, LL b)
{
    return b == 0?a:gcd(b, a%b);
}
LL hs[MOD],head[MOD],next[MOD],id[MOD],top;
void insert(LL x, LL y)
{
    LL k = x%MOD;
    hs[top] = x, id[top] = y, next[top] = head[k], head[k] = top++;
}
LL find(LL x)
{
    LL k = x%MOD;
    for(LL i = head[k]; i != -1; i = next[i])
        if(hs[i] == x)
            return id[i];
    return -1;
}
LL mult(LL a, LL b, LL c)
{
    a %= c; b %= c;
    LL ret = 0, tmp = a;
    while(b)
    {
        if(b & 1LL)
        {
            ret += tmp;
            if(ret > c) ret -= c;
        }
        tmp <<= 1;
        if(tmp > c) tmp -= c;
        b >>= 1;
    }
    return ret%c;
}
LL BSGS(LL a,LL b,LL c)
{
    memset(head, -1, sizeof(head));
    top = 1;
    LL m = sqrt(c*1.0), j;
    long long x = 1, p = 1;
    for(LL i = 0; i < m; ++i, p = p*a%c)
        insert(p*b%c, i);//存的是(a^j*b, j)
    for(long long i = m; ;i += m)
    {
        if( (j = find(x = mult(x,p,c))) != -1 )//注意x要用mult()函数否则超LL
            return i-j;  //a^(ms-j)=b(mod c)
        if(i > c)
            break;
    }
    return 0;
}
int main()
{
    LL o = 0;
    LL n;
    while(scanf("%lld", &n), n)
    {
        printf("Case %d: ", ++o);
        LL m = n/gcd(n, 8)*9;
        if(gcd(m,10) != 1)
        {
            printf("0\n");
            continue;
        }
        printf("%lld\n", BSGS(10,1,m));
    }
    return 0;
}

Euler

还可以试一试欧拉定理。

/*--------------------------------------------
 * File Name: POJ 3696
 * Author: Danliwoo
 * Mail: [email protected]
 * Created Time: 2015-10-02 14:26:08
--------------------------------------------*/

#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
#include <algorithm>
#include <cmath>
using namespace std;
#define N 44725
#define LL long long
LL num[N], prim[N];
int cnt = 0;
void get_prim()
{
    for(int i = 0;i < N;i++) num[i] = i;
    for(int i = 2;i < N;i++) if(num[i])
    {
        for(int j = i*i;j < N;j += i)
            num[j] = 0;
        prim[cnt++] = i;
    }
}
LL phi(LL n)
{
    LL ans = n;
    for(int i = 0;prim[i]*prim[i]<=n;i++) if(n%prim[i] == 0)
    {
        ans -= ans/prim[i];
        while(n%prim[i] == 0) n /= prim[i];
    }
    if(n != 1)
        ans -= ans/n;
    return ans;
}
LL gcd(LL a, LL b)
{
    return b == 0?a:gcd(b, a%b);
}
LL mult(LL a, LL b, LL c)
{
    a %= c; b %= c;
    LL ret = 0, tmp = a;
    while(b)
    {
        if(b & 1LL)
        {
            ret += tmp;
            if(ret > c) ret -= c;
        }
        tmp <<= 1;
        if(tmp > c) tmp -= c;
        b >>= 1;
    }
    return ret%c;
}
LL po(LL a, LL k, LL m)
{
    if(k == 0) return 1;
    if(k == 1) return a%m;
    LL t = po(a, k/2, m);
    t = mult(t, t, m);
    if(k & 1LL) t *= a;
    return t%m;
}
LL solve(LL x, LL p, LL m, LL f)
{
    LL d = po(10, x, m);
    if(d == 1)
    {
        if(x%p == 0)
            return solve(x/p, p, m, f+1);
        else
            return x;
    }
    if(f == 0) return x;
    return x*p;
}
int main()
{
    get_prim();
    int o = 0;
    LL n;
    while(scanf("%lld", &n), n)
    {
        printf("Case %d: ", ++o);
        LL m = n/gcd(n, 8)*9;
        if(gcd(m,10) != 1)
        {
            printf("0\n");
            continue;
        }
        if(po(10, 1, m) == 1)
        {
            printf("1\n");
            continue;
        }
        LL x = phi(m);
        LL ans = x, t = x;
        for(int i = 0; prim[i]*prim[i] <= x && i < cnt;i++) if(ans%prim[i] == 0)
        {
            while(t % prim[i] == 0) t /= prim[i];
            ans = solve(ans, prim[i], m, 0);
        }
        if(t != 1)
            ans = solve(ans, t, m, 0);
        ans = ans == x ? 0 : ans;
        printf("%lld\n", ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/sodacoco/article/details/81517624