poj3358 Period of an Infimite Bimary Expansion

题目大意

链接

把分数转化为二进制小数,找出二进制小数的最小循环节长度以及开始位置。

思路

有理数n的第k位小数应为(n*2^k)mod\ 2

这里用分数p/q表示,则第 k 位小数位$(\frac{p}{q}*2^k)mod\ 2=(p*2^k)/q mod 2$,同时后k位小数为$(p*2^k )mod\ q$;若周期开始位置位x,长度为y,则$ (p*2^x\ mod\ q\equiv(p*2^{(x+y)} \ mod\ q$。y)

那么有

$q|p*2^x*(2^y-1)$

由于p、q互素,则$q|2^x*(2^y-1)$

显然,x的最小值即为q中素因子2的幂;而$q=q<<x$后,$2^y\equiv1\ mod\ q$,y的一个值即为$\varphi(q)$,y的最小值为$\varphi(q)$的一个因数。

注意

  • 先化简分数!
  • $\varphi(q)$不一定是最小的y!
  • 数据很大,可用快速积和快速幂边算边模。

代码

 1 #include<cstring>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<algorithm>
 5 
 6 using namespace std;
 7 
 8 const int Ma=1000006;
 9 long long q,p;
10 
11 long long phi(long long n)
12 {
13     long long ret=n;
14     for(int i=2;i*i<=n;i++)
15     {
16         if(n%i==0)
17         {
18             while(n%i==0)
19             {
20                 ret-=ret/i;
21                 while(n%i==0)n/=i;
22             }
23         }
24     }
25     if(n>1)ret=ret-ret/n;
26     return ret;
27 }
28 
29 long long gcd(long long x,long long y)
30 {
31     if(y==0)return x;
32     else return gcd(y,x%y);
33 }
34 
35 long long qmulti(long long a,long long b,long long mo)
36 {
37     long long ret=0;
38     while(b)
39     {
40         if(b&1)ret=(ret+a)%mo;
41         b>>=1;
42         a=(a+a)%mo;
43     }
44     return ret;
45 }
46 
47 long long qpow(long long a,long long b,long long mo)
48 {
49     long long ret=1;
50     while(b)
51     {
52         if(b&1)ret=qmulti(ret,a,mo)%mo;
53         a=qmulti(a,a,mo)%mo;
54         b>>=1;
55     }
56     return ret%mo;
57 } 
58 
59 int main()
60 {
61     int cnt=0;
62     while(scanf("%lld/%lld",&p,&q)!=EOF)
63     {
64         cnt++;
65         if(p==0)
66         {
67             printf("Case #%d: 1,1 \n",cnt);
68             continue;
69         }
70         long long g=gcd(p,q);
71         p/=g;q/=g;
72         long long x=1,y;
73         while(!(q&1))q>>=1,x++;
74         y=phi(q);
75         long long t=y;
76         for(long long i=2;i<=t/i;i++)
77         {
78             while(y%i==0&&(qpow(2,y/i,q)==1))
79             {
80                 y/=i;
81             }
82         }
83         printf("Case #%d: %lld,%lld \n",cnt,x,y);
84     }
85     return 0;
86 }

猜你喜欢

转载自www.cnblogs.com/LiqgNonqfu/p/10807141.html