poj3696 The Luckiest number

即求出一个 (x) 使得 (L|8 imes (10^x-1)/9),记 (d=(L,8))

[L|8 imes (10^x-1)/9 Leftrightarrow frac{9L}{d}|(10^x-1) Leftrightarrow 10^x equiv 1 pmod {frac{9L}{d}} ]

引理:((a,n)=1),则满足 (a^x equiv 1 pmod n) 的最小 (x) 必为 (varphi(n)) 的约数。
证明: 假设不可,则 (varphi(n)=qx+r)(a^x equiv 1 pmod n Leftrightarrow a^{qx} equiv 1 pmod n),又 (a^{varphi(n)} equiv 1 pmod n),则 (a^r equiv 1 pmod n)(r<x),矛盾,证毕。
因此枚举 (varphi(9L/d)) 的约数一一验证即可。

#include <iostream>
#include <cstdio>
using namespace std;
typedef long long ll;
ll l, ans;
int n;
ll gcd(ll a, ll b){
	return !b?a:gcd(b, a%b);
}
ll getPhi(ll x){
	ll re=x;
	for(ll i=2; i*i<=x; i++)
		if(x%i==0){
			re = re / i * (i - 1);
			while(x%i==0)	x /= i;
		}
	if(x>1)	re = re / x * (x - 1);
	return re;
}
ll mul(ll a, ll b, ll p){
	ll re=0;
	while(b){
		if(b&1)	re = (re + a) % p;
		a = (a + a) % p;
		b >>= 1;
	}
	return re;
}
ll ksm(ll a, ll b, ll p){
	ll re=1;
	while(b){
		if(b&1)	re = mul(re, a, p);
		a = mul(a, a, p);
		b >>= 1;
	}
	return re;
}
int main(){
	while(scanf("%lld", &l)!=EOF){
		if(!l)	break;
		ans = 0x3f3f3f3f3f3f3f3f;
		ll d=gcd(l, 8);
		ll phi=getPhi(9*l/d);
		for(ll i=1; i*i<=phi; i++)
			if(phi%i==0){
				if(ksm(10, i, 9*l/d)==1)
					ans = min(ans, i);
				if(ksm(10, phi/i, 9*l/d)==1)
					ans = min(ans, phi/i);
			}
		printf("Case %d: %lld
", ++n, ans==0x3f3f3f3f3f3f3f3f?0:ans);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/poorpool/p/8507259.html