• Period of an Infinite Binary Expansion POJ


    Period of an Infinite Binary Expansion

     POJ - 3358

    题意:给一个分数,让求其二进制形式的最小循环节ans2和循环节开始的位置ans1。

    以下内容转自http://blog.csdn.net/u013508213/article/details/42496543

    小数二进制的转换方法就是不断*2,mod 分母。

    比如:1/10  2/10  4/10  8/10  16/10  32/10...

    模后:1/10  2/10  4/10  8/10    6/10    2/10...

    这时出现了重复,并且这个重复就是最小循环。

    设从x位置到y位置循环节的分子表示为:2^y = 2^x (mod p)

    稍微变身一下:2^y - 2^x = 0 (mod p) , 

                               2^x(2^(y - x ) - 1) = 0 (mod p),

    所以: p | 2^x(2^(y - x ) - 1),把p一直除到不能被整除就是最小的循环部分起始位置x,

    然后上式变成了:2^(y-x)   -  1 = 0 (mod p'). 

    即: 2^(y - x)  =  1 (mod p').

    又到达了欧拉定理的某种设定之中,根据欧拉定理,t = y - x = elur_phi(p'),枚举同上从小到大枚举 t  的约数,满足此式子就得解。

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <cmath>
     4 #include <iostream>
     5 #include <algorithm>
     6 #define ll long long
     7 using namespace std;
     8 
     9 ll gcd(ll a, ll b){
    10     return b?gcd(b,a%b):a;
    11 }
    12 
    13 ll quickmul(ll a,ll b,ll m){
    14     ll res=0,temp=a%m;
    15     while(b){
    16         if(b&1) res=(res+temp)%m;
    17         b>>=1;
    18         temp=(temp+temp)%m;
    19     }
    20     return res;
    21 }
    22 ll quickpow(ll a,ll b,ll m){
    23     ll res=1,temp=a%m;
    24     while(b){
    25         if(b&1) res=quickmul(res,temp,m);
    26         b>>=1;
    27         temp=quickmul(temp,temp,m);
    28     }
    29     return res;
    30 }
    31 
    32 ll get_phi(ll x){
    33     ll m=sqrt(x+0.5);
    34     ll ans=x;
    35     for(ll i=2;i<=m;i++){
    36         if(x%i==0){
    37             ans=ans/i*(i-1);
    38             while(x%i==0) x/=i;
    39         }
    40     }
    41     if(x>1) ans=ans/x*(x-1);
    42     return ans;
    43 }
    44 ll fac[100010];
    45 int get_fac(ll x){
    46     int cnt=0;
    47     for(ll i=1;i*i<=x;i++){
    48         if(x%i==0){
    49             fac[cnt++]=i;
    50             fac[cnt++]=x/i;
    51         }
    52     }
    53     sort(fac,fac+cnt);
    54     return cnt;
    55 }
    56 int main(){
    57     ll n,m;
    58     int kase=0;
    59     while(scanf("%lld/%lld",&n,&m)!=EOF){
    60         ll g=gcd(n,m);
    61         n/=g;m/=g;
    62         ll ans1=1;
    63         while(m%2==0){
    64             ans1++;
    65             m/=2;
    66         }
    67         ll phi=get_phi(m);
    68         int cnt=get_fac(phi);
    69         ll ans2=phi;
    70         for(int i=0;i<cnt;i++){
    71             if(quickpow(2,fac[i],m)==1){
    72                 ans2=fac[i];
    73                 break;
    74             }
    75         }
    76         printf("Case #%d: %lld,%lld
    ",++kase,ans1,ans2);
    77     }
    78     return 0;
    79 }
    View Code

    发现如果直接从1开始枚举会超时~

    先预处理因子,排序,直接枚举因子~



    如果数据小的话,可以用下面这个

     1 #include<iostream>
     2 #include <cstdio>
     3 #include<map>
     4 #define ll long long
     5 using namespace std;
     6 map<ll,ll> a;
     7 int main(){
     8     ll n,m;
     9     int kase=0;
    10     while (scanf("%lld/%lld",&n,&m)!=EOF){
    11         a.clear();
    12         a[n]=1;
    13         ll d=1,x;
    14         while (1) {
    15             n=(n*2)%m;d++;
    16             x=a[n];
    17             if (x>0) {
    18                 printf("Case #%d: %lld,%lld
    ",++kase,x,d-x);
    19                 break;
    20             } 
    21             a[n]=d;
    22             if (n==0) {
    23                 printf("Case #%d: %lld,%lld
    ",++kase,x,1);
    24                 break;
    25             }
    26         }
    27     }
    28 }
    View Code

    下面这个?

     1 #include <iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<cmath>
     6 #include<vector>
     7 using namespace std;
     8 const int MAXN=150015;
     9 typedef long long LL;
    10 const LL INF=1008610010LL;
    11 int a[MAXN],b[MAXN],c[MAXN],to[MAXN];
    12 bool v[MAXN];
    13 LL gcd(LL a,LL b){
    14     if(!a)return b;
    15     return gcd(b%a,a);
    16 }
    17 int main()
    18 {
    19     int cases;cases=1;
    20     for(int iii=1;;++iii){
    21         LL x,y;
    22         if(scanf("%lld%lld",&x,&y)==EOF)break;
    23         LL temp=gcd(x,y);
    24         x/=temp;
    25         y/=temp;
    26         LL ans1=1,ans2=1,x1=1,y1=y;
    27         while(!(y&1)&&y){++ans1;y>>=1;}
    28         x1=1;y1=y;
    29         for(;;++ans2){
    30             if(y1==1){ans2=0;break;}
    31             x1=(x1<<1)%y1;
    32             if(!(x1-1))break;
    33         }
    34 
    35         printf("%lld %lld
    ",ans1,ans2);
    36     }
    37 }
    View Code
  • 相关阅读:
    C#获取本地IP地址
    C#中将字符串转换成数值
    JavaScript实现基于对象的双端队列
    Java网络编程
    JavaScript实现基于对象的队列
    JavaScript实现基于对象的栈
    JavaScript实现基于数组的栈
    发送短信按钮倒计时案例
    JavaScript动态显示时间
    html
  • 原文地址:https://www.cnblogs.com/yijiull/p/7434678.html
Copyright © 2020-2023  润新知