poj3696

欧拉定理,对于正整数a,n,若gcd(a,n)=1,则有a^euler(n)=1(mod n)。

快速幂取模算法,只要p*2在long long范围内都可以计算,对于算法中long long * long long的情况可能超界,但是我们可以用一种类似于快速幂的方法来进行次乘法计算,即快速幂是用乘法代替幂计算以便及时取模,而此算法则是用加法代替乘法计算及时取模,把快速幂中的乘法换成加法,平方换成乘2即可。

题意:给出数字L,问一个各位数字都是8的L的倍数是否存在,若存在,输出其最小长度。

分析:欧拉定理,我们可以列出方程(10^x - 1) / 9 = L * k / 8,推出(10^x - 1) * 8 = k * 9L,我们现在想要把它化成10^x=1(mod p)的形式,因此我们要看能从这个等式中找到10^x-1是谁的倍数,且要保证p中一定要包含L,且不包含k。我们需要这样做,让等式变为(10^x-1)*a=k*b的形式,且b中要包含L且不包含k,要求gcd(a,b)=1。如果满足以上条件我们就可以证明(10^x-1)是b的倍数了,因为要使等式成立,组成b的因子在等式左边,没有包含在a中,则必然包含在(10^x-1)中。现在若gcd(8,9L)=1则等式符合要求了,但是无法证明它等于1,所以我们将等式改写(10^x-1)*(8/gcd(8,9L))=k*(9L/gcd(8,9L)),这回a,b就互质了。所以我们让p=9L/gcd(8,9L)。

然后我们就有10^x-1=0(mod p),即10^x=1(mod p)。这样就符合了欧拉定理的形式。

现在若gcd(10, p)=1则x必然有解,因为x=phi(p)即可。但我们现在要求的是最小正整数解,mod p乘法是有循环节的,即设循环节为r,那么10^x==10^(x%r)。x=0的时候10^0=1(mod p),有因为在一个循环中乘法结果是不会有重复数字的,即对于xi != xj且xi < r, xj < r,则有10^xi != 10^xj。因此要使得等式10^x=1(mod p)成立,必须有x%r=0。因此最小正整数解就是第一个循环节。那么既然phi(p)是解说明它在循环节上,是循环节的倍数,因此只要枚举phi(p)的所有约数其中一定有循环节,找到最小的可以使得等式成立的即为所求。

对于gcd(10, p) != 1的情况,方程一定无解。设gcd(10,p)=g,因为10^x % g = 0,可以看作10^x=g*y。设p=g*z,10^x %p = (g*y)%(g*z) = g*y-n*(g*z) = g*(y-n*z) 所以一定是g的倍数,不会等于1。

综上,我们代码处理过程为,先求phi(p),p=9L/gcd(8,9L)。然后用跟好phi(p)的效率求其所有约数,对于每个约数,用快速幂验证是否满足方程10^x=1(mod p)。找到满足方程的最小的一个。

View Code
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cstdio>
#include <cstring>
using namespace std;

#define maxn (1 << 16)

long long n;
long long factor[maxn];

long long euler(long long n)
{
    long long ret = n;
    for (long long i = 2; i * i <= n; i++)
        if (n % i == 0)
        {
            ret = ret / i * (i - 1);
            while (n % i == 0)
                n /= i;
        }
    if (n > 1)
        ret = ret / n * (n - 1);
    return ret;
}

long long mult(long long a, long long b, long long p)
{
    long long ret = 0;
    while (b)
    {
        if (b & 1)
            ret = (ret + a) % p;
        a = 2 * a % p;
        b >>= 1;
    }
    return ret;
}

long long power(long long x, long long n, long long p)
{
    long long ret = 1;
    x %= p;
    while (n)
    {
        if (n & 1)
            ret = mult(ret, x, p);
        x = mult(x, x, p);
        n >>= 1;
    }
    return ret;
}

long long work()
{
    n *= 9;
    for (int i = 0; i < 3; i++)
        if (n % 2 == 0)
            n /= 2;
        else
            break;
    long long p = n;
    if (p % 2 == 0 || p % 5 == 0)
        return 0;
    long long phi = euler(p);
    int cnt = 0;
    for (long long i = 1; i * i <= phi; i++)
        if (phi % i == 0)
        {
            factor[cnt++] = i;
            factor[cnt++] = phi / i;
        }
    sort(factor, factor + cnt);
    for (int i = 0; i < cnt; i++)
        if (power(10, factor[i], p) == 1)
            return factor[i];
    return 0;
}

int main()
{
//    freopen("t.txt", "r", stdin);
    int t = 0;
    while (scanf("%lld", &n), n)
    {
        t++;
        printf("Case %d: ", t);
        printf("%lld\n", work());
    }
    return 0;
}
原文地址:https://www.cnblogs.com/rainydays/p/2754760.html