The Luckiest number -- 数论题

本文介绍了一种算法,用于解决寻找最小的全部由数字8组成的数,该数能够被给定的数L整除的问题。利用了欧拉同余定理、欧拉函数和质数筛法等数论知识,通过代码实现了解题过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

题意:给你一个数L,让你求出最小的一个数能被L整除,这个数满足每一位都是8。

input

8
11
16
0

output

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

所用数论知识:

  • 欧拉同余定理
  • 欧拉函数
  • 质数筛法

第一步列式 :(10 ^ x - 1) / 9是x个连续的8的表达
代码如下

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#define il inline
#define re register
using namespace std;
typedef long long ll;
const ll maxn = 50010;
ll L, ans, tot;
ll q, d, p;
//推公式使用到的数
ll v[maxn], vis[maxn];
//v => 保存L以内所有质数 
vector<ll> T;
il void Prime() {
	memset(vis, 0, sizeof(vis));
	ll k = 0;
	for(re ll i = 2; i < maxn; ++i) {
		if(!vis[i]) {
			v[k++] = i;
			for(re ll j = i+i; j < maxn; j += i)
				vis[j] = 1;
		}
	}
	return ;
}
il ll GetEuler(ll x) {
	ll res = x;
	for(re ll i = 0; v[i]*v[i] <= x; ++i) {
		if(x % v[i] == 0) {
			res = res/v[i] * (v[i]-1);
			while(x%v[i] == 0) 
				x /= v[i];
		}
	}
	if(x > 1)//为质数 
		res = res/x * (x-1);
	return res;
}
il ll GetGcd(ll a, ll b) {
	return b==0 ? a : GetGcd(b, a%b);
}
il ll Mul(ll x, ll a, ll mod) {
	ll res = 0;
	while(a > 0) {
		if(a & 1) 
			res = (res + x) % mod;
		x = (x + x) % mod;
		a >>= 1;
	}
	return res % mod;
}
il ll Pow(ll x, ll a, ll mod) {
	ll res = 1;
	while(a > 0) {
		if(a & 1) 
			res = Mul(res, x, mod) % mod;
		x = Mul(x, x, mod) % mod;
		a >>= 1;
	}
	return res % mod;
}
il void Pre(ll L) {
	T.clear();
	for(re ll i = 0; v[i]*v[i] <= L; ++i) {
		while(L % v[i] == 0) {
			T.push_back(v[i]);
			L /= v[i]; 
		}
	}
	if(L > 1) T.push_back(L);
	return ; 
}
int main() {
	tot = 0; Prime();
	while(scanf("%lld", &L) && L != 0) {
		printf("Case %lld: ", ++tot);
		d = GetGcd(8, L);
		//cout << d << endl;
		q = 9*L/d;
		//cout << q << endl;
		//注意判断不合法的条件 
		if(GetGcd(q, 10) != 1) printf("0\n");
		else {
			ll cnt = GetEuler(q);
			//cout << cnt << endl;
			ll mi = cnt;
			bool flag = 1;
			while(flag) {
				Pre(cnt);
				flag = 0;
				for(re ll i = 0; i < T.size(); ++i) {
					if(Pow(10, cnt/T[i], q) == 1) {
						flag = 1;
						mi = min(mi, cnt/T[i]);
					}
				}
				cnt = mi;
			}
			printf("%lld\n", mi);
		}
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值