「POJ3696」The Luckiest number【数论,欧拉函数】

题解

一道数论欧拉函数和欧拉定理的入门好题。
虽然我提交的时候POJ炸掉了,但是在hdu里面A掉了,应该是一样的吧。
首先我们需要求的这个数一定可以表示成 ( 1 0 x − 1 ) 9 × 8 \frac{(10^x-1)}{9}\times 8 9(10x1)×8
那么可以列出一个下面的方程
( 1 0 x − 1 ) 9 × 8 = L × k \frac{(10^x-1)}{9}\times 8=L\times k 9(10x1)×8=L×k

d = g c d ( 9 L , 8 ) = g c d ( L , 8 ) d=gcd(9L,8)=gcd(L,8) d=gcd(9L,8)=gcd(L,8)

8 9 ( 1 0 x − 1 ) = L k \frac89(10^x-1)=Lk 98(10x1)=Lk

8 ( 1 0 x − 1 ) d = 9 L k d \frac{8(10^x-1)}d=\frac{9Lk}{d} d8(10x1)=d9Lk

p = 8 d , q = 9 L d p=\frac8d,q=\frac{9L}d p=d8,q=d9L,易证 p p p q q q互质。

p ( 1 0 x − 1 ) = q k p(10^x-1)=qk p(10x1)=qk

可得 q ∣ 1 0 x − 1 q|10^x-1 q10x1,所以得到了 1 0 x ≡ 1 ( m o d   q ) 10^x\equiv1(mod \ q) 10x1(mod q)

根据欧拉定理,当 10 10 10 q q q互质,必定有一组解,是 φ ( q ) \varphi(q) φ(q)

那么最小的一组解一定是 φ ( q ) \varphi(q) φ(q)的一个约数。


那么欧拉函数计算一下,然后枚举一下约数,快速幂判断一下就好了。

代码

#include <cstdio>
#include <cmath>
#include <iostream>
#include <algorithm>
#define ll long long
#define db double  
using namespace std;
ll L, ans;
bool fg;
ll gcd(ll x, ll y) { return y == 0 ? x : gcd(y, x % y) ; }
ll mulmod(ll x, ll y, ll mod) {
	ll res = 0ll;
	for (; y; y >>= 1) { if (y & 1) res = (res + x) % mod; x = (x << 1) % mod; }
	return res;
}
ll power(ll x, ll y, ll mod) {
	ll res = 1ll;
	for (; y; y >>= 1) { if (y & 1) res = mulmod(res, x, mod); x = mulmod(x, x, mod); }
	return res;
}
ll euler(ll x) {
	ll res = x;
	for (ll i = 2; i * i <= x; i ++) {
		if (x % i == 0) {
			res = res / i * (i - 1);
			while (x % i == 0) x /= i;
		}
	}
	if (x > 1) res = res / x * (x - 1);
	return res;
}
int main() {
	int cas = 0;
	while (~scanf("%I64d", &L) && L) {
		ll d = gcd(L, 8), q = 9 * L / d; fg = 0;
		if (gcd(q, 10) != 1) printf("Case %d: 0\n", ++ cas);
		else {
			ll phi = euler(q), m = sqrt((db)(phi));
			ans = phi; 
			for (int i = 1; i <= m; i ++) 
				if (phi % i == 0 && power(10, i, q) == 1) { ans = i; fg = 1; break; } 
			if (!fg) for (int i = m; i >= 2; i --) {
				if (phi % i == 0 && power(10, phi / i, q) == 1) { ans = phi / i; break; }
			}
			printf("Case %d: %I64d\n", ++ cas, ans);
		}
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值