POJ 3358 数论

来源:互联网 发布:985的学生知乎 编辑:程序博客网 时间:2024/05/21 04:17

求二进制小数循环节

这题必须要先吐槽一下出题的人,某些细节没有写清楚,比如整除的情况下是怎样?(或许没有那样的数据....还有p=0的情况是怎样,这些特殊情况很难说清),数据范围也没用说明。结果把本菜坑的一塌糊涂。。。(T..T)

回归正题:求二进制小数的循环节和循环起点。刚开始这题后来没思路,看解题报告发现人家把小数化为分数时,果断关闭窗口。自己去独立完成。。。(话说这也没想到也忒2B了吧。。。。T...T)这样就找到了规律:

以1/10为例:1/10 2/10 4/10 8/10 16/10 32/10 64/10....(小数话二进制每次*2取整,这不就和分子*2,以分母为余数取模一样吗。。。NC无下限)

取模后:1/10 2/10 4/10 8/10 6/10 2/10 4/10 咦,这不就是个循环吗?循环节为4,循环起点为2,正好与题目相符。。如何去找循环节和循环起点?

由于是二进制,所以分子可以表示为2^x,而模数即q

2^x=2^y(mod p),2^x(2^(y-x)-1)=0(mod p),即p|2^x(2^(y-x)-1),首先把p尽量整除2直到不能整除为止,这个步骤的次数就是满足原式最小的x,并得到p'。2^(y-x)=1(mod p')

根据欧拉定理,t=y-x=phi(p')满足此式。但不是最小值,枚举phi(p')约数。

话说这题被坑了N多个WA。。。题目没说清,自己有两处处理的不好,哎。。。伤不起呀。。

#include <iostream>#include <cstdio>#include <cmath>#include <cstdlib>#include <cstring>#include <vector>#define ss(p,q) scanf("%I64d/%I64d",&p,&q)#define N 1000005#define M 30#define ll __int64#define pb push_back#define Max 9223372036854775807ULLusing namespace std;ll a[N];vector<int>b;void prime(){    int i,j;    b.clear();    for (i=2;i<N;i++)        if (!a[i])        {            b.pb(i);            for (j=i*2;j<N;j+=i) a[j]=1;        }}ll euler(ll n){    ll res=n,i;    if (n==1) return 0;    for (i=0;i<b.size();i++)        if (n%b[i]==0)         {            res=res/b[i]*(b[i]-1);            while (n%b[i]==0) n/=b[i];            if (n==1) break;        }    if (n!=1) res=res/n*(n-1);    return res;}ll gcd(ll p,ll q){    if (p<q) return gcd(q,p);    else if (p%q==0) return q;    else return gcd(q,p%q);}ll js(int x,ll q){    ll i=0,res=1,curr=2%q;    while (x>0)    {        if (x&1) res=(res*curr)%q;        i++;        x>>=1;        curr=(curr*curr)%q;    }    return res;}ll deal(ll t,ll q){    int i,i0;    ll mmin=Max;    for (i=1;i*i<=t;i++)           if (t%i==0)        {            if (js(i,q)==1) return i;            i0=t/i;            if (js(i0,q)==1&&i0<mmin) mmin=i0;        }    return mmin;}int main(){    ll p,q,i,t,x,cas=0;    prime();    while (ss(p,q)!=EOF)    {        cas++;        x=0;        if (p==0)        {            cout<<"Case #"<<cas<<": "<<1<<','<<1<<endl;            continue;        }        ll y=gcd(p,q);        p/=y;q/=y;        ll q1=q;        while (q1%2==0)        {            x++;            q1/=2;        }         x++;        t=euler(q1);        if (t!=0) t=deal(t,q1);         cout<<"Case #"<<cas<<": "<<x<<','<<t<<endl;    }    return 0;}


 

 

原创粉丝点击