POj 3358 二进制小数循环节

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Feynman1999/article/details/82354516

二进制循环小数循环节

problem

Let {x} = 0.a*1*a*2*a*3… be the binary representation of the fractional part of a rational number *z. Suppose that {x} is periodic then, we can write

{x} = 0.a*1*a*2…*ar(a**r+1*a**r*+2…a**r+s)w

for some integers r and s with r ≥ 0 and s > 0. Also, (a**r+1*a**r*+2…a**r+s)w*denotes a nonterminating and repeating binary subsequence of {*x}.

The subsequence x*1 = *a*1*a*2 … *ar*is called the *preperiod of {x} and x*2 = *a**r+1*a**r*+2 … a**r+s is the period of {x}.

Suppose that |x*1| and |*x*2| are chosen as small as possible then *x*1 is called the *least preperiod and x*2 is called the *least period of {x}.

For example, x = 1/10 = 0.0001100110011(00110011)w and 0001100110011 is a preperiod and 00110011 is a period of 1/10.

However, we can write 1/10 also as 1/10 = 0.0(0011)w and 0 is the least preperiod and 0011 is the least period of 1/10.

The least period of 1/10 starts at the 2nd bit to the right of the binary point and the the length of the least period is 4.

Write a program that finds the position of the first bit of the least period and the length of the least period where the preperiod is also the minimum of a positive rational number less than 1.

Input

Each line is test case. It represents a rational number p/q where p and q are integers, p ≥ 0 and q > 0.

Output

Each line corresponds to a single test case. It represents a pair where the first number is the position of the first bit of the least period and the the second number is the length of the least period of the rational number.

Sample Input

1/10 
1/5 
101/120 
121/1472

Sample Output

Case #1: 2,4 
Case #2: 1,4 
Case #3: 4,4 
Case #4: 7,11

思路

给p/q 求其转为二进制后循环节从哪开始 以及循环节的最短长度

二进制看下一位是多少即乘2 相当于左移1位 然后如果超过了分母就减去分母

举个例子

1/10 2/10 4/10 8/10 16/10=6/10 32/10=2/10(开始循环)

所以现在的问题是

对于p/q 先出去gcd,然后要求 p 2 i p 2 j   ( m o d   q )

变换后可得 p 2 i ( 2 j i 1 ) 0   ( m o d   q )

也就是说 q   |   p 2 i ( 2 j i 1 )

由于p,q互质

所以 q   |   2 i ( 2 j i 1 )

由于 ( 2 j i 1 ) 是奇数,则 q 中有多少2的次幂, i 就是多少 且i+1就是循环节出现之前的长度,即所求

然后假设q去除完2因子之后为m 则解 2 x 1   ( m o d   m ) 的最小解

由欧拉定理: a φ ( m ) 1   ( m o d   m ) w h e r e g c d ( a , m ) = 1

  • 注意 φ ( m ) 不一定是最小模m为1的指数,但可以证明这些指数都是 φ ( m ) 的因子。因此可以将 φ ( m ) 质因子分解,用每个素因子试除,每个素因子除到模 m 不为1为止(此时要乘回去)。

解得的X即为最后所求循环节长度

#include<iostream>
#include<vector>
using namespace std;

typedef long long ll;

ll gcd(ll a,ll b)
{
    if(b==0) return a;
    return gcd(b,a%b);
}

ll fast_exp(ll a,ll b,ll c)
{
    ll res=1;
    while(b)
    {
        if(b&1) res=res*a%c;
        a=a*a%c;
        b>>=1;
    }
    return res;
}

ll get_phi(ll x)
{
    ll res=x;
    for(int i=2;i*i<=x;++i){
        if(x%i==0){
        res-=res/i;
        do{
            x/=i;
        }while(x%i==0);
        }
    }
    if(x>1) res-=res/x;
    return res;
}

ll string2ll(string s)
{
    ll sum=0;
    for(int i=0;i<s.size();++i){
        sum=sum*10+s[i]-'0';
    }
    return sum;
}

int main()
{
    //cout<<get_phi(10000000)<<endl;
    ios::sync_with_stdio(false);
    ll p,q;
    string s;
    int t=0;
    while(cin>>s)
    {
        std::size_t pos = s.find("/");
        p=string2ll(s.substr(0,pos));
        q=string2ll(s.substr(pos+1));
        t++;
//        if(p==0){
//            cout<<"Case #"<<t<<": "<<1<<","<<1<<endl;
//        }
        ll d=gcd(p,q);
        p=p/d;
        q=q/d;
        int i=0;
        while((q&1)==0)
        {
            q>>=1;
            i++;
        }
        ll phi=get_phi(q);
        ll tp=phi;
        vector<ll> prime;
        for(int i=2;i*i<=phi;++i){
            if(phi%i==0)
            {
                prime.push_back(i);
                do{
                    phi/=i;
                }while(phi%i==0);
            }
        }
        if(phi>1) prime.push_back(phi);
        for(int i=0;i<prime.size();++i){
            while(fast_exp(2,tp,q)==1 && tp%prime[i]==0)
            {
                tp/=prime[i];
            }
            if(fast_exp(2,tp,q)!=1) tp*=prime[i];
        }
        cout<<"Case #"<<t<<": "<<i+1<<","<<tp<<endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Feynman1999/article/details/82354516