Root(hdu5777+扩展欧几里得+原根)

Root

                                                                         Time Limit: 30000/15000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
                                                                                                           Total Submission(s): 34    Accepted Submission(s): 6


Problem Description
Given a number  sum(1sum100000000) ,we have  m  queries which contains a pair ( xi,yi ) and would like to know the smallest nonnegative integer  ki satisfying  xkii=yi mod p  when the prime number  p (sum mod p=0) (ps: 00=1 )
 

Input
The first line contains a number T, indicating the number of test cases. 

For each case, each case contains two integers  sum,m(1sum100000000,1m100000)  in the first line. 

The next  m  lines will contains two intgeers  xi,yi(0xi,yi1000000000)
 

Output
For each test case,output "Case # X :" and  m  lines.( X  is the case number) 

Each line cotain a integer which is the smallest integer for ( xi,yi ) ,if we can't find such a integer just output "-1" without quote.
 

Sample Input
  
  
1 175 2 2 1 2 3
 

Sample Output
  
  
Case #1: 0 3
Hint
175 =527 20 mod 5 = 1 23 mod 7 = 1 So the answer to (2,1) is 0
 

Source



比较经典一道扩展欧几里得 



现在,我们首先来解决下原根的问题:简单的解释可以参考:>>原根<<  

 

资源下载:http://download.csdn.net/detail/u010579068/8993383


不急看懂的,可以先去切道 定义题    链接:1135 原根  

 解题 http://www.cnblogs.com/yuyixingkong/p/4722821.html



转载请注明出处:寻找&星空の孩子     

 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5377



#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<map>
using namespace std;
typedef long long ll;
const int maxn=1e6+1;
const int maxv=1e5+1;
bool isnp[maxv];
int prime[maxv],pnum;//素数数组,素数个数
int cas;
void get_prime()//素数打表
{
    pnum=0;
    int i,j;
    memset(isnp,0,sizeof(isnp));
    isnp[0]=isnp[1]=true;
    for(i=2; i<maxv; i++)
    {
        if(!isnp[i])prime[pnum++]=i;
        for(j=0; j<pnum&&prime[j]*i<maxv; j++)
        {
            isnp[i*prime[j]]=true;
            if(i%prime[j]==0)break;
        }
    }
}
ll qukpow(ll k,ll base,ll p)
{
    ll res=1;
    for(; k; k>>=1)
    {
        if(k&1)res=(res*base)%p;
        base=(base*base)%p;
    }
    return res;
}
ll ppow(ll a,ll b,ll mod)
{
    ll c=1;
    while(b)
    {
        if(b&1) c=c*a%mod;
        b>>=1;
        a=a*a%mod;
    }
    return c;
}
ll fpr[maxv];

ll find_primitive_root(ll p)//求p的原根    g^(p-1) = 1 (mod p); 求g
{
    ll cnt=0,num=p-1,res;
    int i;
    if(p==2)return 1;
    for(i=0; i<pnum && prime[i]*prime[i]<=num && num>1 ; i++)
    {
        if(num%prime[i]==0)//
        {
            fpr[cnt++]=prime[i];
            while(num%prime[i]==0)num/=prime[i];
        }
    }
    if(num>1)fpr[cnt++]=num;//fpr[]存的是p-1的因子
    for(res=2; res<=p-1; res++)//暴力
    {
        for(i=0; i<cnt; i++)
            if(ppow(res,p/prime[i],p)==1)break;
        if(i>=cnt)return res;
    }
    return -1;
};

const int mod=1e6+7;

struct solve
{
    struct HashTable
    {
        int top,head[mod];
        struct Node
        {
            int x,y,next;
        } node[mod];
        void init()
        {
            top=0;
            memset(head,0,sizeof(head));
        }
        void insert(ll x,ll y)
        {
            node[top].x=x;
            node[top].y=y;
            node[top].next=head[x%mod];
            head[x%mod]=top++;
        }
        ll query(ll x)
        {
            for(int tx=head[x%mod]; tx; tx=node[tx].next)
                if(node[tx].x==x)return node[tx].y;
            return -1;
        }
    } mp;

    ll p;
    ll discretelog(ll prt,ll a) //取对数
    {
        ll res,am=ppow(prt,maxn-1,p),inv=ppow(a,p-2,p),x=1;
        for(ll i=maxn-1;; i+=(maxn-1))
        {
            if((res=mp.query((x=x*am%p)*inv%p))!=-1)
            {
                
                return i-res;
            }
            if(i>p)break;
        }
        return -1;
    }
    void ex_gcd(ll a,ll b,ll &d,ll &x,ll &y)//扩展欧几里得 x为最后需要的k
    {
        if(!b)
        {
            d=a;
            x=1;
            y=0;
        }
        else
        {
            ex_gcd(b,a%b,d,y,x);
            y-=x*(a/b);
        }
    }

    ll proot;
    void init()
    {
        mp.init();
        ll tmp,x,y,d;
        int i;
        proot=find_primitive_root(p);//找到素数p的原根
        for(i=0,tmp=1; i<maxn-1; i++,tmp=tmp*proot%p)
            mp.insert(tmp%p,i*1ll);
    }
    ll query(ll x,ll y)
    {
        ll d;
        x%=p;
        y%=p;
        
        if(y==1)return 0;
        else if(x==0)
        {
            if(y==0)return 1;
            else return -1;
        }
        else if(y==0)return -1;
        else
        {
            ll s=discretelog(proot,x);
            
            ll t=discretelog(proot,y);
            
            ex_gcd(s,p-1,d,x,y);
            if(t%d)return -1;
            else
            {
                ll dx=(p-1)/d;
                x=(x%dx+dx)%dx;
                x*=(t/d);
                x=(x%dx+dx)%dx;
                return x;
            }
        }
    }
} sol[32];
int main()
{
    int i,j,q,con,T;
    ll sum,x,y;
    scanf("%d",&T);
    get_prime();
    cas=1;
    while(cas<=T)
    {
        con=0;
        scanf("%I64d %d",&sum,&q);

        for(i=0; i<pnum&&prime[i]*prime[i]<=sum&&sum!=1; i++)
        {
            if(sum%prime[i]==0)//素数存起来
            {
                sol[con].p=prime[i];
                sol[con].init();
                con++;
                while(sum%prime[i]==0)sum/=prime[i];
            }
        }
        if(sum>1)
        {
            sol[con].p=sum;
            sol[con].init();
            con++;
        }

        printf("Case #%d:\n",cas++);

        for(i=0; i<q; i++)
        {
            scanf("%lld %lld",&x,&y);

            ll res=1e18,tmp;
            for(j=0; j<con; j++)
            {
 
                tmp=sol[j].query(x,y);
                if(tmp!=-1)res=min(res,tmp);
            }
            if(res==1e18)res=-1;
            printf("%I64d\n",res);
        }
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值