POJ3696 The Luckiest number

原题面:https://vjudge.net/problem/POJ-3696

题目大意:给定一个正整数L(1<=L<=2e9),问至少多少个8连在一起组成的正整数是L的倍数?

输入描述:多组输入,每次输入一个L,直到L为0结束输入。

输出描述:对于每组数据,输出至少多少个8连在一起可以组成L的倍数。

样例输入:

8
11
16
0

样例输出:

Case 1: 1
Case 2: 2
Case 3: 0

分析:x个8组成的正整数可以写作8(pow(10,x)-1)/9。题目就是想让我们求出一个最小的满足情况的x。L|8(pow(10,x)-1)/9<-->9L|8(pow(10,x)-1)<-->9L/d|pow(10,x)-1<-->pow(10,x)==1(mod9L/d)。若正整数a,n互质,则满足pow(a,x)==1(mod n)的最小正整数x0是phi(n)的约数。注意该死的慢速乘,题目给的数据范围中间爆了long long,真是有毒,wa死我了,几天了才A。

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
ll divisor[10000007];
int cnt;
ll gcd(ll a,ll b) {
    return !b ? a : gcd(b, a % b);
}
ll phi(ll n) {
    ll ans = n;
    for (ll i = 2; i * i <= n; i++) {
        if (n % i == 0) {
            ans = ans - ans / i;
            while (n % i == 0) n /= i;
        }
    }
    if (n > 1) ans = ans - ans / n;
    return ans;
}
void depart(ll n) {
    cnt = 0;
    for (ll i = 1; i * i <= n; i++) {
        if (n % i == 0) {
            divisor[cnt++] = i;
            if (n != i * i) {
                divisor[cnt++] = n / i;
            }
        }
    }
}
ll mul(ll a,ll b,ll m){
    ll res=0;
    while(b){
        if(b&1)
            res=(res+a)%m;
        a=(a+a)%m;
        b>>=1;
    }
    return res;
}
ll spow(ll a,ll b,ll m) {
    ll res = 1;
    a %= m;
    while (b) {
        if (b & 1)
            res = mul(res, a, m);
        a = mul(a, a, m);
        b >>= 1;
    }
    return res;
}
int main() {
    ll L, d, ans;
    int kase = 0;
    while (cin>>L) {
        if(L==0) break;
        d = gcd(L, 8LL);
        ans = 0;
        ll m = 9 * L / d;
        if (gcd(10, m) != 1) {
            printf("Case %d: %lld\n", ++kase, ans);
            continue;
        }
        depart(phi(m));
        sort(divisor, divisor + cnt);
        //unique(divisor.begin(),divisor.end());
        for (int i = 0; i < cnt; i++) {
            if (spow(10, divisor[i], m) == 1) {
                ans = divisor[i];
                break;
            }
        }
        printf("Case %d: %lld\n", ++kase, ans);// "Case " << ++kase << ": " << ans << endl;
    }
    return 0;
}
posted @ 2019-12-28 09:27  SwiftAC  阅读(161)  评论(0编辑  收藏  举报