Clever Y [Bzoj 1467]

45 篇文章 0 订阅
33 篇文章 0 订阅

题目地址请点击——


Clever Y


Description

小Y发现,数学中有一个很有趣的式子: XY mod Z = K 给出 X Y Z ,我们都知道如何很快的计算 K
但是如果给出 X Z K ,你是否知道如何快速的计算 Y 呢?


Input

本题由多组数据(不超过20组),每组测试数据包含一行三个整数 X Z K 0X,Z,K109)。 输入文件一行由三个空格隔开的 0 结尾。


Output

对于每组数据:如果无解则输出一行 No Solution,否则输出一行一个整数 Y(0Y<Z) ,使得其满足 XY mod Z = K ,如果有多个解输出最小的一个 Y <script type="math/tex" id="MathJax-Element-213">Y</script>。


Sample Input

5 58 33
2 4 3
0 0 0


Sample Output

9
No Solution


Solution

扩展 Baby-Step-Giant-Step 模板题。


Code

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>

#define LL long long
#define HASH_MOD 786433

using namespace std;

LL x,z,k,cnt=0,xxx,yyy,ans;

LL ex_gcd(LL x,LL y,LL &a,LL &b){
    if(y==0){a=1;b=0;return x;}
    LL fa,fb;
    LL c=ex_gcd(y,x%y,fa,fb);
    a=fb;
    b=fa-fb*(x/y);
    return c;
}

struct map{
    LL h[800000],v[800000],nxt[800000],ne[800000];
    void clear(){
        memset(nxt,-1,sizeof nxt);
        memset(h,-1,sizeof h);
        ne[786433]=0;
        for(LL i=0;i<786433;i++)ne[i]=i;
    }
    LL fi(LL x){
        LL tmp=x,pre;
        while(tmp!=ne[tmp])tmp=ne[tmp];
        while(x!=tmp){pre=ne[x];ne[x]=tmp;x=pre;}
        return tmp;
    }
    void insert(LL x,LL y){
        LL mx=x%HASH_MOD;
        while(nxt[mx]!=-1)
            mx=nxt[mx];
        nxt[mx]=fi(0);
        ne[nxt[mx]]=ne[nxt[mx]]+1;
        h[nxt[mx]]=x;
        v[nxt[mx]]=y;
    }
    LL find(LL x){
        LL mx=x%HASH_MOD;
        while(x!=h[mx]&&nxt[mx]!=-1)mx=nxt[mx];
        if(x!=h[mx])return -1;
        return v[mx];
    }
};

map hash;

int main(){

    while(scanf("%lld%lld%lld",&x,&z,&k)!=EOF&&(x||z||k)){
        hash.clear();
        LL gg=ex_gcd(x,z,xxx,yyy),d=1,MAXN,tmp,tmp2,tt;
        while(gg!=1){
            if(k%gg!=0){printf("No Solution\n");goto nxt;}
            k/=gg;z/=gg;d*=x/gg;
            cnt++;
            gg=ex_gcd(x,z,xxx,yyy);
        }
        x%=z;k%=z;
        MAXN=ceil(sqrt((double)z)),tmp=1;
        if(k==d%z){printf("0\n");goto nxt;}
        hash.insert(1,0);
        for(LL i=1;i<MAXN;i++){
            tmp=tmp*x%z;
            if(d*tmp%z==k){
                if(i<=cnt){printf("%lld\n",i);goto nxt;}
                else{printf("%lld\n",i+cnt);goto nxt;}
            }
            hash.insert(tmp,i);
        }
        tmp2=tmp,tt=tmp*x%z;
        for(LL i=MAXN;i<=cnt;i++){
            tmp2=tmp2*x%z;
            if(d*tmp%z==k){printf("%lld\n",i);goto nxt;}
        }
        tmp=tt;
        if(d*tmp%z==k){
            if(MAXN<=cnt){printf("%lld\n",MAXN);goto nxt;}
            else{printf("%lld\n",MAXN+cnt);goto nxt;}
        }
        ex_gcd(d*tmp,z,xxx,yyy);
        xxx=(xxx*k%z+z)%z;
        if((ans=hash.find(xxx))!=-1){printf("%lld\n",ans+MAXN+cnt);goto nxt;}
        for(LL i=2;i<=MAXN;i++){
            tmp=tmp*tt%z;
            ex_gcd(d*tmp,z,xxx,yyy);
            xxx=(xxx*k%z+z)%z;
            if((ans=hash.find(xxx))!=-1){printf("%lld\n",ans+MAXN*i+cnt);goto nxt;}
        }
        printf("No Solution\n");
        nxt:;
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值