1. 程式人生 > 實用技巧 >[HDU2462] The Luckiest number

[HDU2462] The Luckiest number

前言

差一點就推出來了qaq

題目

HDU

題目大意:

多組詢問,0結束,問\(x=88...888\)(len個\(8\)),且\(L|x\)的最小\(len\),如果無解輸出\(0\)

輸出格式見樣例

講解

首先我們可以將\(x\)表示為\((10^{len}-1)/9*8\)

那麼\(L|(10^{len}-1)/9*8\)\(L*9|(10^{len}-1)*8\)

\(d=gcd(L*9,8)\),所以\(L*9/d|(10^{len}-1)*8/d\)

\(L'=L*9/d\),因為\(L*9/d\)\(8/d\)互質,所以\(L'|(10^{len}-1)\)

那麼一定可以寫成這種形式:\(10^{len}\% L'=1\)

此時如果\(10\)\(L'\)不互質,一定無解

否則\(10^{\phi(L')}\% L'=1\)\(\phi(L')\)即為答案

嗎?

我們要求最小的答案,所以我們只需列舉\(\phi(L')\)的因數,再用快速冪判斷即可

值得注意的是在快速冪期間,中間變數可能會爆\(long\ long\),所以要使用防爆乘法

程式碼

LL gcd(LL x,LL y)
{
	if(!y) return x;
	return gcd(y,x%y);
}
LL getphi(LL x)
{
	LL ret = x;
	for(int i = 2;1ll * i * i <= x;++ i)
	{
		if(x % i == 0)
		{
			ret = ret / i * (i-1);
			while(x % i == 0) x /= i;
		}
	}
	if(x > 1) ret = ret / x * (x-1);
	return ret;
}
LL gsc(LL x,LL y,LL MOD)
{
	LL ret = 0;
	while(y){if(y & 1) ret = (ret + x) % MOD;x = (x << 1) % MOD;y >>= 1;}
	return ret;
}
LL qpow(LL x,LL y,LL MOD)
{
	LL ret = 1;
	while(y){if(y & 1) ret = gsc(ret,x,MOD);x = gsc(x,x,MOD);y >>= 1;}
	return ret;
}

int main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	while(1)
	{
		n = Read();
		if(!n) return 0;
		n *= 9;
		LL d = gcd(n,8),ans,phi;
		n /= d;
		if(gcd(n,10) > 1) {printf("Case %d: 0\n",++tot);continue;}
		ans = phi = getphi(n);
		for(int i = 1;1ll*i*i <= phi;++ i)
			if(phi % i == 0)
			{
				if(qpow(10,i,n) == 1) {ans = i;break;}
				if(qpow(10,phi/i,n) == 1) ans = phi/i;
			}
		printf("Case %d: %lld\n",++tot,ans);
	}
	return 0;
}