首页 > 代码库 > [bzoj 3031] 理科男

[bzoj 3031] 理科男

给定一个技术分享进制分数 技术分享 求是否是循环小数,且求出循环节长度

 

暴力

il int find(int p){    int head=last[p%mod];    while(head&&pr[head].p!=p)head=pr[head].next;    if(!head)head=++siz;    return head;}int main(){    T=gi;    while(T--){siz=0;memset(last,0,sizeof(last));        ll p,q,k;        p=gi;q=gi;k=gi;        ll d=gcd(p,q);                p/=d;q/=d;        p%=q;        for(int i=1;;i++){            p*=k;            if(!(p%q)){                printf("%d 0\n",i);                break;            }            int t=find(p);            if(!pr[t].id)pr[t]=(data){i,p};            else{                printf("%d %d\n",pr[t].id-1,i-pr[t].id);                break;            }            p%=q;        }    }    return 0;}

正解:

首先设技术分享一个序列技术分享,技术分享表示原数小数点后i位,那么技术分享

然后余数技术分享

技术分享

上面暴力是计算到技术分享这样一对的时候停止

 

那么考虑a的性质 如果技术分享 ,那么技术分享

技术分享

如果技术分享 那么技术分享

就是出现了更早的重复,所以最早的重复肯定是在p=1,说明这样形式的只有纯循环小数

如果满足技术分享

于是技术分享

然后就是求一个K模B的阶的问题。

阶很好求。。

#include<queue>#include<map>#include<cstdio>#include<string.h>#include<iostream>#include<algorithm>using namespace std;typedef long long ll;typedef pair<int,int>Pii;const int inf=0x7fffffff;const ll infll=(1ll<<60);#define dbg(n)    cerr<<#n"="<<n<<endl;#define Ri register int#define gc getchar()#define il inlineil ll read(){    bool f=true;    register ll x=0;char ch;    while(!isdigit(ch=gc))        if(ch==-)f=false;    while(isdigit(ch)){        x=(x<<1)+(x<<3)+ch-0;        ch=gc;    }    return f?x:-x;}#define X first#define Y second#define gi read()#define FO(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout);inline ll gcd(ll a,ll b){    return b?gcd(b,a%b):a;}map<ll,int> Calc(ll x){    map<ll,int> prime;    for(int i=2;(ll)i*i<=x;i++)        if(x%i==0){            int sum=0;            while(x%i==0)x/=i,sum++;            prime[i]=sum;        }    if(x>1)prime[x]=1;    return prime;}il ll Euler_phi(ll x,const map<ll,int>& prime){    ll ans=x;    for(map<ll,int>::const_iterator i=prime.begin();i!=prime.end();i++)        if(i->Y)ans=ans/i->X*(i->X-1);    return ans;}il ll Mul(ll a,ll b,ll mod){    ll ans=0,p=a%mod;    while(b){        if(b&1)ans=(ans+p)%mod;        p=(p+p)%mod;        b>>=1;    }    return ans;}il ll Mod(ll a,ll b,ll mod){    ll ans=1,p=a%mod;    while(b){        if(b&1)ans=Mul(ans,p,mod);        p=Mul(p,p,mod);        b>>=1;    }    return ans;}ll A,B,K;int main(){    int T;    cin>>T;    while(T--){        A=gi;B=gi;K=gi;        ll d=gcd(A,B);        A/=d;B/=d;        map<ll,int> prime_B=Calc(B),prime_K=Calc(K);        int M=0;ll tmpB=B;        for(map<ll,int>::const_iterator  i=prime_K.begin();i!=prime_K.end();i++){            int p=prime_B[i->X];prime_B[i->X]=0;            M=max(M,(p+i->Y-1)/i->Y);            while(p)                tmpB/=i->X,p--;        }        ll R=0;        if(tmpB!=1){            ll phi_B=Euler_phi(tmpB,prime_B);            R=phi_B;            prime_B=Calc(R);            for(map<ll,int>::const_iterator i=prime_B.begin();i!=prime_B.end();i++){                int p=i->Y;                while(p){                    if(Mod(K,R/i->X,tmpB)==1)                        p--,R/=i->X;                    else break;                }            }        }        cout<<M<<" "<<R<<endl;    }    return 0;}

[bzoj 3031] 理科男