HDU 2462 - The Luckiest number(欧拉定理)

The Luckiest number

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1935    Accepted Submission(s): 603

Problem Description

Chinese people think of '8' as the lucky digit. Bob also likes digit '8'. Moreover, Bob has his own lucky number L. Now he wants to construct his luckiest number which is the minimum among all positive integers that are a multiple of L and consist of only digit '8'.

Input

The input consists of multiple test cases. Each test case contains exactly one line containing L(1 ≤ L ≤ 2,000,000,000).

The last test case is followed by a line containing a zero.

Output

For each test case, print a line containing the test case number( beginning with 1) followed by a integer which is the length of Bob's luckiest number. If Bob can't construct his luckiest number, print a zero.

Sample Input

8

11

16

0

Sample Output

Case 1: 1

Case 2: 2

Case 3: 0

Source

2008 Asia Hefei Regional Contest Online by USTC

 

欧拉定理:a^x 1(mod m),那么 x = euler(m);

推导:

(10^x - 1)/ 9 * 8  ==  n * p ; 则10^x  - 1 == n * p / 8 * 9;

设m == 9*n / gcd(n,8);

那么(10^x - 1)== m * p' ; 可以得到10 ^ x 1 (mod m);

可以知道,当m 和 10不互质的时候,肯定不符合答案;

然后x == euler(m),然后答案就是满足这个方程的是euler(m)的因数的最小的值;

在找满足方程的euler(m)的最小因数的时候为了防止超时,可以从访问到一半的位置,之后再进行除法进而判断后面的数的情况;

  需要注意的是,对于10^x,由于m太大,直接快速幂相乘的时候会超long long。,需要乘法转化一下。

参考的代码:

#include <bits/stdc++.h>
using namespace std;
#define clr(a) memset(a,0,sizeof(a))
#define line cout<<"-----------------"<<endl;

typedef long long ll;
const int maxn = 1e5+10;
const int MAXN = 1e6+10;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9+7;
const int N = 1010;

ll gcd(ll a,ll b){
	return b == 0 ? a : gcd(b , a%b);
}
ll Euler(ll n){//欧拉函数模板
    ll ans = 1;
    for(int i = 2; i * i <= n; i++){
        if(n % i == 0){
            n /= i;
            ans *= (i - 1);
            while(n % i == 0){
                n /= i;
                ans *= i;
            }
        }
    }
    if(n > 1) ans *= (n-1);
    return ans ;
}
ll Mul(ll x , ll y , ll mod){//快速幂取模模板
	ll ans = 0;
	while(y){
		if(y & 1){
			ans = (ans + x) % mod;
		}
		x = x * 2 % mod;
		y >>= 1;
	}
	return ans ;
}
ll pow_mod(ll x , ll n , ll mod ){
	ll ans = 1;
	ll t = x % mod ;
	while(n) {
		if(n & 1){
			ans = Mul(ans , t, mod);
		}
		t = Mul(t , t , mod);
		n >>= 1 ;
	}
	return ans ;
}

int main(){
	int cas = 1;
	ll n,ans;
	while(scanf("%lld",&n)!=EOF && n){
		ll m = n / gcd(n , 8) * 9;
		if(gcd(10 , m) != 1)
			ans = 0;
		else{
			ll cnt = Euler(n);
			ans = 1e18 ;
			for( ll i = 1 ; i * i <= cnt ; i ++){
				if( cnt % i == 0 ){
					if( pow_mod (10 , i , m) == 1)
						ans = min(ans , i);
					if( pow_mod(10 , cnt/i ,m) == 1)
						ans = min(ans , cnt/i);
				}
			}
		}
		printf("Case %d: %lld\n", cas ++ , ans );
	}
	return 0;
}

自己的代码:

#include <bits/stdc++.h>
using namespace std;
#define clr(a) memset(a,0,sizeof(a))
#define line cout<<"-----------------"<<endl;

typedef long long ll;
const int maxn = 1e5+10;
const int MAXN = 1e6+10;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9+7;
const int N = 1010;

vector<ll> ve;

ll gcd(ll a,ll b){
	return b == 0 ? a : gcd(b , a%b);
}
void get_prime(ll n){
	for(ll i = 1 ; i * i <= n ; i++){
		if(n % i == 0){
			ve.push_back(i);
			if(i * i != n)
				ve.push_back(n/i);
		}
	}
}
ll Euler(ll n){//欧拉函数模板
    ll ans = 1;
    for(int i = 2; i * i <= n; i++){
        if(n % i == 0){
            n /= i;
            ans *= (i - 1);
            while(n % i == 0){
                n /= i;
                ans *= i;
            }
        }
    }
    if(n > 1) ans *= (n-1);
    return ans ;
}
//下面两个函数是为了防止 快速幂爆 long long 
ll Mul(ll x , ll y , ll mod){//快速幂取模模板
	ll ans = 0;
	while(y){
		if(y & 1){
			ans = (ans + x) % mod;
		}
		x = x * 2 % mod;
		y >>= 1;
	}
	return ans ;
}
ll pow_mod(ll x , ll n , ll mod ){
	ll ans = 1;
	ll t = x % mod ;
	while(n) {
		if(n & 1){
			ans = Mul(ans , t, mod);
		}
		t = Mul(t , t , mod);
		n >>= 1 ;
	}
	return ans ;
}

int main(){
	int cas = 1;
	ll n,ans;
	while(scanf("%lld",&n)!=EOF && n){
		ve.clear();
		ll m = n / gcd(n , 8) * 9;
		if(gcd(10 , m) != 1)
			ans = 0;
		else{
			ans = Euler(m);
			get_prime(ans);//讲ans因数分解的结果保存
			sort(ve.begin(),ve.end());//从小大大排序
			for(ll i=0;i<ve.size();i++){
				if( pow_mod(10ll , ve[i] ,m) == 1 ){//如果满足要求
					ans = ve[i];
					break;
				}
			}
		}
		printf("Case %d: %lld\n", cas ++ , ans );
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值