poj 3358 Period of an Infinite Binary Expansion (费马小定理+分数化二进制小数)

探讨了如何将分数形式的小数转换为二进制,并找出其循环节的起始位置及长度。通过数学推导得出算法实现思路,并提供完整的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:将一个小于1的小数表示成二进制形式。输出二进制形式下,小数部分第几开始循环,循环节长度是多少?

解析:将一个分数化成小数,转化成二进制后寻找循环节
对于分数P/Q而言,首先化成最简,调整为P'=P/GCD(P,Q) Q'=Q/GCD(P,Q)
我们知道转化成二进制,其实就是不断乘2,如果大于1,则去掉1,当前位为1,否则为0.
表示成分数的时候便是P/Q,2*P/Q如果分子大于分母,则减掉,也相当于取余。
于是我们假设在第I位的时候开始循环,第J位出现重复。
而出现循环反正在分数上便是分母和分子都相同,由于在这里分母是不变的,只考虑分子
那么(P'*2^I)%Q'==(P'*2^J)%Q ;
一个同余式,作 些调整 P'*(2^J-2^I)==0(MOD Q') P'*2^I*(2^(J-I)-1)==0(MOD Q')
变成P'*2^I*(2^(J-I)-1)|Q’
其中P'与Q'互质。那么2^I*(2^(J-I)-1)|Q’
而(2^(J-I)-1是奇数,那么I的值便是Q'里面有多少个2^的幂,第一部分已经解决
假设Q'除掉2的幂之后为Q''


若A与P互质,则A^PHI(P) == 1 (MOD P)
所以2^X ==1 (mod Q'') 必定存在解。
我们要求的是最小的解,则枚举PHI(Q'')的因子,从小开始判断
2^X==1(MOD Q'')

#include <functional>
#include <algorithm>
#include <iostream>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <numeric>
#include <cstring>
#include <cassert>
#include <cstdio>
#include <string>
#include <vector>
#include <bitset>
#include <queue>
#include <stack>
#include <cmath>
#include <ctime>
#include <list>
#include <set>
#include <map>
using namespace std;
typedef long long LL;
template<class T> T gcd(T a,T b)
{
    return b?gcd(b,a%b):a;
}
LL exlur(LL x)
{
   LL res=1,i;
   for(i=2;i*i<=x;i++)
   {
       if(x%i==0)
       {
           res*=i-1; x/=i;
           while(x%i==0)
           {
                res*=i; x/=i;
           }
       }
   }
   if(x>1) res*=x-1;
   return res;
}
LL ppow(LL a,LL n,LL mmod)
{
    LL res=1,p=a;
    while(n)
    {
        if(n&1) res=(res*p)%mmod;
        p=(p*p)%mmod;
        n>>=1;
    }
    return res;
}
vector<LL> f;
int main()
{
    long long  p,q,i,d;
    int t=1,len1;
    char c;
    while(~scanf("%lld/%lld",&p,&q))
    {
        if(p==0)
        {
             printf("Case #%d: %d,%d\n",t++,0,0);

             continue;
         }
        d=gcd(p,q);
        p/=d;
        q/=d;
        len1=0;
        while(!(q&1))
        {
            q/=2;
            len1++;
        }
        LL x=exlur(q);
        f.clear();
        for(i=2;i*i<=x;i++)
        {
           if(x%i==0)
           {
               f.push_back(i);
               if(i*i==x) break;
               f.push_back(x/i);
           }
        }
        f.push_back(x);
        sort(f.begin(),f.end());
        int j;
        LL ans;
        for(j=0;j<f.size();j++)
        {
          if(ppow(2,f[j],q)==1)
           {   ans=f[j]; break;}
        }

        printf("Case #%d: %d,%lld\n",t++,len1+1,ans);

    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值