Description
吃过草莓刨冰之后,Vani和cl有些疲倦地坐在一个长椅上。
“呐,玩得开心吗?”Vani忽然问道。
“嗯……很,很开心的说。”
“那么,我有一个问题想要问你呢。”
cl的脸有点红了起来。
“嗯……好吧。问、问吧……我会告诉你的哦……”
“那好。对于一个分数A / B……”
“嗯……哎?哎?!”
“……就是这个问题。我觉得这个问题好纠结啊……”
Vani淡定地说完这句话。
“啊?!哈啊?!”
对于给定的分数 A / B,求其在 K 进制下是有限小数还是循环小数。如果是有限小数,求小数点后的位数;如果是循环小数,则求混循环部分和循环节的长度又分别是多少。
注意,循环节指的是最短循环节,且混循环部分的长度也指最短。
Input
第一行一个正整数 T,表示测试数据的数目。
每个测试数据包含三个空格分隔的整数 A, B, K。含义如题目所示。
Output
对于每个测试数据,在单独的一行内输出两个空格分隔的整数 M, R。
其中 M 表示混循环部分的长度,R 表示循环节的长度。
如果 A / B 在 K 进制下是有限小数,则 R = 0,M 为小数点后面的位数;如果 A / B 在 K 进制下是纯循环小数,则 M = 0。
$minimizespace M,Rspace s.t.$
$frac{A}{B}=frac{x}{(K^R-1)K^M}$
将$frac{A}{B}$化为最简分数后,答案只和$B,K$有关若$gcd(B,K)>1$则有混循环部分,将$B$不断除以$gcd(B,K)$直到互质,除的次数即为$M$
R即为求$frac{B}{gcd(B,K^M)}$在模K意义下与K互质的数构成的乘法群中的阶,答案是$phi(K)$的约数,可以试除得到
#include<cstdio> typedef long long i64; i64 gcd(i64 a,i64 b){ for(i64 c;b;c=a,a=b,b=c%b); return a; } i64 phi(i64 x){ i64 y=x; for(int i=2;i64(i)*i<=x;++i)if(x%i==0){ y=y/i*(i-1); do x/=i;while(x%i==0); } if(x>1)y=y/x*(x-1); return y; } i64 mul(i64 a,i64 b,i64 p){ i64 c=0; for(;b;b>>=1,a=(a<<1)%p)if(b&1)c=(c+a)%p; return c; } i64 pw(i64 a,i64 n,i64 p){ i64 v=1; for(;n;n>>=1,a=mul(a,a,p))if(n&1)v=mul(v,a,p); return v; } i64 cal(i64 A,i64 B){ i64 x=phi(B),y=x; for(int i=2;i64(i)*i<=x;++i)if(x%i==0){ while(y%i==0&&pw(A,y/i,B)==1)y/=i; do x/=i;while(x%i==0); } if(x>1&&pw(A,y/x,B)==1)y/=x; return y; } int main(){ int T; for(scanf("%d",&T);T;--T){ i64 a,b,c; scanf("%lld%lld%lld",&a,&b,&c); i64 g=gcd(a,b); a/=g,b/=g; int a1=0; while(1){ i64 x=gcd(b,c); if(x==1)break; b/=x; ++a1; } printf("%d %lld ",a1,b==1?0ll:cal(c,b)); } return 0; }