BZOJ2480: Spoj3105 Mod

    已知数a,p,b,求满足a^x≡b(mod p)的最小自然数x。p不一定是素数。

    先附上AekdyCoin大牛的题解:http://hi.baidu.com/aekdycoin/item/236937318413c680c2cf29d4

    然后我们来证明算法的正确性。

    不妨认为我们消因子后,a->a,b->b',c->c',d,e(指文中的D),除去的gcd之积为f,且(a,c‘)=1

    那么其实 a^d=f*e,然后我们用BSGS求解 e*a^x=b' mod c' 因为(a,c‘)=1

    而且x就是(a^inf,c)

    然后假设我们得到了一个解  e*a^x=b' mod c' 考虑回推出原同余方程的解。

    由裴蜀定理值存在唯一的  e*a^x+c'*y=b'  (注意现在是等号,而不是模意义)

    我们在等式两边乘以f,就得到了 a^d*a^x+c*y=b ,也就是a^(d+x)=b mod c,这说明x+d是原方程的解。

    我知道公式写成这样是没人耐心看的

    还是看代码比较亲切

    

map<int,int>mp;
inline int gcd(int x,int y){return y?gcd(y,x%y):x;}
inline int power(int x,int y,int p)
{
    int t=1;
    for(;y;y>>=1,x=(ll)x*x%p)
     if(y&1)t=(ll)t*x%p;
    return t;
}
inline int solve(int a,int b,int c)
{
    a%=c;b%=c;
    for(int i=0,j=1;i<=50;i++,j=(ll)j*a%c)if(j==b)return i;
    int d=0,e=1%c,t;
    while((t=gcd(a,c))!=1)
    {    
        if(b%t)return -1;
        c/=t;b/=t;d++;e=(ll)e*a/t%c;
    }
    mp.clear();
    int m=ceil(sqrt(c));
    for(int i=0,j=1;i<m;i++,j=(ll)j*a%c)mp[(ll)b*j%c]=i;
    a=power(a,m,c);
    for(int i=0,j=e;i<=m;i++,j=(ll)j*a%c)
     if(i&&mp.find(j)!=mp.end())
       return  i*m-mp[j]+d;
    return -1;
}
int main()
{
    freopen("input.txt","r",stdin);
    freopen("output.txt","w",stdout);
    while(1)
    {
        int a=read(),c=read(),b=read(),t;
        if(!(a||b||c))break;
        if((t=solve(a,b,c))>=0)printf("%d\n",t);
        else printf("No Solution\n");
    }
    return 0;
}

 

     

posted @ 2015-01-11 09:06  ZYF-ZYF  Views(330)  Comments(0Edit  收藏  举报