小红的循环小数

众所周知,所有的无限循环小数都可以写成分数的形式
小红想让你判断循环节长度为k的无限循环小数的分母是否可能是p。你能帮帮她吗?
共有q次询问。

输入描述
第一行输入一个正整数 q q q,代表询问次数。
接下来的 q q q行,每行输入两个正整数k,p,代表一次询问。
1 ≤ q ≤ 1 0 5 1\leq q \leq 10^5 1q105
1 ≤ k , p ≤ 1 0 9 1\leq k,p \leq 10^9 1k,p109
输出描述
输出 q q q行,如果存在一个分子 q q q,满足 q / p q/p q/p为循环节长度为k的无限循环小数,则输出"Yes"。否则输出"No"。
输入示例1

5
1 6
2 4
3 37
100000 3
2 37

输出示例1

Yes
No
Yes
Yes
No

说明
第一组询问,1/6=0.166666……,循环节长度为 1。
第二组询问,显然分母为 4 的小数均为有限小数。
第三组询问,8/37=0.216216216216……,循环节长度为 3。
第四组询问,1/3=0.3333……,显然长度 100000 也是它的循环节长度

💖 思路

👨‍🏫 参考地址
在这里插入图片描述
② 单位分数 1/m,若分母 m 都为 1 0 n − 1 10^n-1 10n1,则化成小数后的结果如下

1 9 = 0.1111111 … … \frac{1}{9} = 0.1111111…… 91=0.1111111……

1 99 = 0.010101 … … \frac{1}{99} = 0.010101…… 991=0.010101……

1 999 = 0.001001001 … … \frac{1}{999} = 0.001001001…… 9991=0.001001001……

这种小数叫做单位无限循环小数
0.251251251 … … = 251 × 0.001001001 … … = 251 × 1 999 0.251251251……=251×0.001001001……=251\times \frac{1}{999} 0.251251251……=251×0.001001001……=251×9991

其中右边分数的分母 999 = 1 0 3 − 1 999=10^3-1 999=1031,即循环节 = 3 = 10的指数

言归正传:题目求是否存在一个分子 x ,在分母为 p 的情况下,结果为无限循环小数 z 的循环节长度为 k,,假设现在的循环节为 a

即有 z = a × 1 1 0 k − 1 = x p z=a×\frac{1}{10^k-1}=\frac{x}{p} z=a×10k11=px

Tips:分子 x 可以为任意数

a 1 0 k − 1 = a × x a p \frac{a}{10^k-1}=\frac{a\times \frac{x}{a}}{p} 10k1a=pa×ax

Tips:即 x a \frac{x}{a} ax也可以是任意数( a ≠ 0 a\neq0 a=0)

换而言之 x a = p 1 0 k − 1 \frac{x}{a} = \frac{p}{10^k-1} ax=10k1p

上结论:分母 p 转化为 1 0 k − 1 10^k-1 10k1 的形式

  • p 的质因数中不含 2 或 5 以外的质数 :有限小数
  • p 的质因数中不含 2 或 5 两种:则必有一个 p n = 1 0 k − 1 p^n=10^k-1 pn=10k1
  • 质因数中既有2或5,又有其它质因数,可通分为 ( 1 0 n − 1 ) × 1 0 m (10^n-1)\times10^m (10n1)×10m,此时可转化为无限循环小数,再移动m位小数点(通常称为“混循环”)

💖 解题步骤

  • 分母的质因数只含 2 或 5:有限小数
  • 否则:
    • 1 0 k − 1 10^k-1 10k1 % p == 0,存在分子 x 可以通分成 a
    • else 不存在

💖 AC code

import java.util.*;

class Main
{
	public static void main(String[] args)
	{
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		for (int i = 0; i < n; i++)
		{
			System.out.println(result(sc.nextInt(), sc.nextInt()) ? "Yes" : "No");
		}
	}

	public static boolean result(int k, int p)
	{
		while (p % 2 == 0)//消去质因子 2
			p /= 2;

		while (p % 5 == 0)//消去质因子 5
			p /= 5;
		if (p == 1)
			return false;
		return (qpow(10, k, p) - 1) % p == 0;
	}

//	快速幂
	private static long qpow(int x, int k, int mod)
	{
		long ans = 1;
		while (k != 0)
		{
			if ((k & 1) != 0)
				ans = ans * x % mod;
			k >>= 1;
			x = x * x % mod;
		}
		return ans;
	}
}
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐