hdu5377 Root

題目鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=5377
題意:
sum,mxi,yi,ki使xkii=yi mod psump
sum<=108,m<=105
分析:離散對數,我們可以採用baby-step算法求解,但是直接做的話單次詢問需要n ,這裏就使用了一個技巧:令x=da mod p ,y=db mod p ,x,ydp ,於是上式就可以化簡爲dak=dbmodp ,由於p是素數,那麼顯然有ak=bmodp1 ,這裏只需要用擴展歐幾里德解一個模方程即可。如何求a,b,仍然需要用baby-step求,但由於每次詢問時候的d都是相同的,假設我們預處理的表的大小是sz,那麼複雜度就降爲sz+qn/sz ,可以看出sz較大的時候複雜度會比較小

#include<bits/stdc++.h>
using namespace std;
const int Inf=1e9;
typedef long long Int;
bool isp[10020];
vector<int>pri;
int cas=1,mul;
int powmod(int x,int y,int mod)
{
    int ret=1;
    while(y)
    {
        if(y&1)ret=ret*(Int)x%mod;
        x=x*(Int)x%mod;
        y>>=1;
    }
    return ret;
}
void exgcd(int a,int b,int &x,int &y)
{
    b?(exgcd(b,a%b,y,x),y-=a/b*x):(x=1,y=0);
}
void getp()
{
    for(int i=2;i<=10000;i++)
    {
        if(!isp[i])
        {
            pri.push_back(i);
            for(int j=i+i;j<=10000;j+=i)
                isp[j]=1;
        }
    }
}
void divide(int x,vector<int>&V)
{
    for(int i=0;i<pri.size()&&pri[i]*pri[i]<=x;i++)
    {
        if(x%pri[i]==0)
        {
            V.push_back(pri[i]);
            while(x%pri[i]==0)x/=pri[i];
        }
    }
    if(x>1)V.push_back(x);
}
int getd(int x)
{
    if(x==2)return 1;
    vector<int>tp;
    divide(x-1,tp);
    for(int i=2;;i++)
    {
        bool flag=1;
        for(int j=0;j<tp.size();j++)
            if(powmod(i,(x-1)/tp[j],x)==1)
            {
                flag=0;
                break;
            }
        if(flag)return i;
    }
    return -1;
}
int Mp1[100000000];
int Mp2[10][10000];
void get(int &a,int tx,int p)
{
    if(Mp1[tx]>=0)a=Mp1[tx];
    else
    {
        int now=tx;
        for(int i=1;i*1000000<=p;i++)
        {
            now=now*(Int)mul%p;
            if(Mp1[now]>=0){a=Mp1[now]+i*1000000;return;}
        }
    }
}
int getrev(int a,int b)
{
    int x,y;
    exgcd(a,b,x,y);
    return x<0?(x+b):x;
}
int main()
{
    getp();
    int _;scanf("%d",&_);
    while(_--)
    {
        int sum,m;scanf("%d%d",&sum,&m);
        vector<int>allp;
        vector<int>small;
        divide(sum,allp);
        int maxx=-1,maxsz;
        for(int i=0;i<allp.size();i++)
            if(allp[i]<10000)
            {
                small.push_back(allp[i]);
            }
            else
            {
                int now=1,x=getd(allp[i]);
                maxx=allp[i];
                mul=powmod(x,maxx-1-1000000%(maxx-1),maxx);
                maxsz=min(1000000,maxx-1);
                for(int j=1;j<maxx;j++)Mp1[j]=-1;
                for(int j=0;j<maxsz;j++)
                {
                    if(Mp1[now]<0)Mp1[now]=j;
                    now=now*(Int)x%maxx;
                }
            }
        for(int i=0;i<small.size();i++)
        {
            memset(Mp2[i],-1,sizeof(Mp2[i]));
            int now=1,x=getd(small[i]);
            for(int j=0;j<small[i]-1;j++)
            {
                if(Mp2[i][now]<0)Mp2[i][now]=j;
                now=now*(Int)x%small[i];
            }
        }
        printf("Case #%d:\n",cas);
        while(m--)
        {
            int x,y;scanf("%d%d",&x,&y);
            int ans=Inf;
            for(int i=0;i<small.size();i++)
            {
                int p=small[i];
                int tx=x%p,ty=y%p;
                if(tx==0)
                {
                    if(ty==0)ans=min(ans,1);
                    else if(ty==1)ans=min(ans,0);
                    continue;
                }
                else if(ty==0)continue;
                int a=Mp2[i][tx],b=Mp2[i][ty];
                int gc=__gcd(a,p-1);
                if(b%gc)continue;
                int k=b/gc*(Int)getrev(a/gc,(p-1)/gc)%((p-1)/gc);
                ans=min(ans,k);
            }
            if(maxx!=-1)
            {
                int p=maxx;
                int tx=x%p,ty=y%p;
                if(tx==0)
                {
                    if(ty==0)ans=min(ans,1);
                    else if(ty==1)ans=min(ans,0);
                }
                else 
                if(ty)
                {
                    int a,b;
                    get(a,tx,p);
                    get(b,ty,p);
                    int gc=__gcd(a,p-1);
                    if(b%gc==0)
                    {
                        int k=b/gc*(Int)getrev(a/gc,(p-1)/gc)%((p-1)/gc);
                        ans=min(ans,k);
                    }
                }
            }
            if(ans==Inf)ans=-1;
            printf("%d\n",ans);
        }
        cas++;
    }

}
發佈了55 篇原創文章 · 獲贊 2 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章