poj 3358 乘二取整法+欧拉定理+快速幂(注意溢出)

题目传送门

//把一个小于1的小数转化为二进制形式,找到最小循环部分的起始位置以及最小循环长度
//欧拉定理  十进制小数转化为二进制:乘二取整法
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long LL;
LL gcd(LL a,LL b)
{
    return b==0?a:gcd(b,a%b);
}
LL ouler(LL n)
{
    LL res=n;
    for(int i=2;1l*i*i<=n;i++)
    {
        if(n==1) break;
        if(n%(LL)i==0) {
            res/=(LL)i;
            res*=((LL)i-1);
            while(n%(LL)i==0) {
                n/=(LL)i;
            }
         }
    }
    if(n!=1) {
        res/=n;
        res*=(n-1);
    }
    return res;
}
LL mul(LL a,LL b,LL m)
{
    LL ans=0;
    while(b)
    {
        if(b&1) ans=(ans+a)%m;
        a=(a<<1)%m;
        b>>=1;
    }
    return ans;
}
LL pow(LL a,LL b,LL m)
{
    LL ans=1;
    while(b)
    {
        if(b&1) ans=mul(ans,a,m);
        a=mul(a,a,m);
        b>>=1;
    }
    return ans;
}
int main()
{
    LL p,q,kase=0;
    while(~scanf("%lld/%lld",&p,&q))
    {
        LL k=gcd(p,q);
        p/=k;
        q/=k;
        LL solve=0;
        while(q%2==0) {
                solve++;
                q/=(LL)2;
        }
        //cout<<solve<<endl;
        LL f=ouler(q);
        LL solve1=f;
        //枚举因子
        for(int i=1;(LL)i*i<=f;i++)
        {
            if(f%i==0) {
                if(pow(2,i,q)==1) {
                    solve1=min(solve1,(LL)i);
                }
                if(pow(2,f/(LL)i,q)==1) {
                    solve1=min(solve1,f/(LL)i);
                }
            }
        }
        //cout<<solve1<<endl;
        printf("Case #%d: ",++kase);
        cout<<solve+1<<","<<solve1<<endl;
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值