zoukankan      html  css  js  c++  java
  • 【POJ3358】Period of an Infinite Binary Expansion-欧拉定理+数论好题

    测试地址:Period of an Infinite Binary Expansion
    题目大意:对于一个小于1的有理数L,将其写成二进制小数形式:0.a1a2...,小数部分无限延伸下去(如果有限就在后面填0)。若这个小数部分可以写成下列形式:a1a2...ar(ar+1ar+2...ar+s)w,其中(s)w表示字符串s重复出现若干次,则称a1a2...ar为一个长为r的前缀,ar+1ar+2...ar+s称为一个长为s的循环。输入一个有理数p/q(0p<q2109)p,q为整数,请你求这个有理数小数部分的最小循环长度,并求出循环最早在哪一位开始出现(即最小前缀长度+1)。
    做法:可恶啊!明明方程都推出来了,可就是做不出来,好气啊,没办法只能看了题解……
    首先我们可以将p/q约分,即令p=p/gcd(p,q),q=q/gcd(p,q),简化计算而又不影响结果。分析题目,一个有理数小数部分的二进制表示可以用二进制转换法(乘二法)得到,那么我们可以得到下面这个序列:2i×p/q(i0),将每一个数的分子模q,得到:(2i×pmodq)/q。将几组数据代入观察,发现分子出现循环,而这个循环长度正好相当于二进制位中的循环长度,那么问题就转化成了求关于i,j的同余方程:2i×p2i+j×p(modq)的一组解,使得i,j最小。可以发现ij就是我们说的最小前缀长度和最小循环长度。
    将式子转换一下变成:(2j1)×p×2i0(modq),也就是说q|(2j1)×p×2i,因为gcd(p,q)=1,所以q|(2j1)×2i,又由于2j1是奇数,所以i就是q中包含的素因子2的数量,原因后面说明。设q=q/2i,则q|2j1,那么问题转化成求关于j的同余方程2j1(modq)的最小正整数解。这时候就表明前面确定i的大小的方法正确的原因了,如果这里gcd(q,2)1,这个同余方程就无解了,所以要去掉q的所有因子2来确保方程必然有解。由欧拉定理得2φ(q)1(modq),可以证明最小解j一定是φ(q)的因子。使用反证法证明,假设最小解j不是φ(q)的因子,那么设r=φ(q)modi,所以r<j,又因为2j1(modq)2φ(q)1(modq),得到2r1(modq),这和j是最小解相矛盾,所以j必然是φ(q)的因子。那么我们就可以用和POJ3696一样的方法来做这道题,这道题我也写过题解,题解在此。这样我们就完美解决了这一题,最后的答案就是i+1,j
    以下是本人代码:

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define ll long long
    using namespace std;
    ll p,q,fac[30];
    
    ll gcd(ll a,ll b)
    {
      return (b==0)?a:gcd(b,a%b);
    }
    
    ll mult(ll a,ll b,ll mod)
    {
      a%=mod,b%=mod;
      ll s=a,sum=0;
      while(b)
      {
        if (b&1)
        {
          sum+=s;
          if (sum>=mod) sum-=mod;
        }
        b>>=1;s<<=1;
        if (s>=mod) s-=mod;
      }
      return sum;
    }
    
    ll power(ll a,ll b,ll mod)
    {
      ll s=a,sum=1;
      while(b)
      {
        if (b&1) sum=mult(sum,s,mod);
        b>>=1;s=mult(s,s,mod);
      }
      return sum;
    }
    
    ll phi(ll x)
    {
      ll p=x;
      for(int i=2;i*i<=x;i++)
        if (!(x%i))
        {
          p=p/i*(i-1);
          while(!(x%i)) x/=i;
        }
      if (x>1) p=p/x*(x-1);
      return p;
    }
    
    void find_factor(ll x)
    {
      fac[0]=0;
      for(int i=2;i*i<=x;i++)
        if (!(x%i))
        {
          fac[++fac[0]]=i;
          while(!(x%i)) x/=i;
        }
      if (x>1) fac[++fac[0]]=x;
    }
    
    int main()
    {
      int t=0;
      while(scanf("%lld/%lld",&p,&q)!=EOF)
      {
        t++;
        ll d=gcd(p,q),i=0,j;
        p/=d,q/=d;
        while(!(q%2)) {q>>=1;i++;}
        i++;
        j=phi(q);
        find_factor(j);
        for(int i=1;i<=fac[0];i++)
        {
          while(1)
          {
            j/=fac[i];
            if (power(2,j,q)!=1)
            {
              j*=fac[i];
              break;
            }
            else if (j%fac[i]) break;
          }
        }
        printf("Case #%d: %lld,%lld
    ",t,i,j);
      }
    
      return 0;
    }
    
  • 相关阅读:
    Entity Framework Core 2.0 新特性
    asp.net core部署时自定义监听端口,提高部署的灵活性
    asp.net core使用jexus部署在linux无法正确 获取远程ip的解决办法
    使用xshell连接服务器,数字键盘无法使用解决办法
    使用Jexus 5.8.2在Centos下部署运行Asp.net core
    【DevOps】DevOps成功的八大炫酷工具
    【Network】Calico, Flannel, Weave and Docker Overlay Network 各种网络模型之间的区别
    【Network】UDP 大包怎么发? MTU怎么设置?
    【Network】高性能 UDP 应该怎么做?
    【Network】golang 容器项目 flannel/UDP相关资料
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793672.html
Copyright © 2011-2022 走看看