数论_同余_欧拉函数_POJ3696_POJ3696_The Luckiest number

天涯浪子 提交于 2019-12-04 15:52:15

点此打开题目页面

思路分析:    设由x个8构成的x位数能够被L整除, d = gcd(L, 8),

    则

, 分析知10与

互质.

引理: 若正整数a, n互质, 则满足

的最小正整数

的约数, 

为欧拉函数. 证明从略:

因此只需枚举

的所有约数, 并使用快速幂检验即可, 需要注意的是快速幂计算乘法的中间结果会超出long long最大表示范围, 需单独写一个64位整数乘法的过程, 具体实现如下AC代码所示:
//POJ3696_The Luckiest number
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long ll;
//返回(a * b) % mod的值 
ll mul(ll a, ll b, ll mod){
	ll res = 0;
	for(; b; b >>= 1, a = (a << 1) % mod) if(b & 1) res = (res + a) % mod;
	return res;
}
ll power(ll a, ll b, ll mod){
	ll res = 1; 
	for(; b; b >>= 1, a = mul(a, a, mod)) if(b & 1) res = mul(res, a, mod);
	return res;	
}
int gcd(int a, int b){
	if(!b) return a;
	return gcd(b, a % b);
}
//将n的所有约数存储于approx中 
void getApprox(ll n, vector<ll> &approx){
	for(int i = 1; i <= sqrt((double)n); ++i){
		if(n % i) continue;
		approx.push_back(i);
		if(i != n / i) approx.push_back(n / i);	
	}
}
//返回n的欧拉函数值 
ll euler(ll n){
	ll res = n;
	for(int i = 2; i <= sqrt((double)n); ++i){
		if(n % i) continue;
		res = res / i * (i - 1);
		while(n % i == 0) n /= i;
	}
	if(n >= 2) res = res / n * (n - 1);
	return res;
}
int main(){
	int sn = 0, L; 
	while(++sn, scanf("%d", &L), L){
		ll tmp = (9ll * L) / gcd(L, 8); int res = 0;
		vector<ll> approx; getApprox(euler(tmp), approx);
		sort(approx.begin(), approx.end());
		for(int i = 0; i < approx.size(); ++i){
			ll t = power(10, approx[i], tmp);
			if(t == 1){
				res = approx[i]; break;
			}
		}
		cout << "Case " << sn << ": " << res << endl;
	}	
	return 0;
} 

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!