bzoj 2242: [SDOI2011]计算器 & BSGS算法笔记

这题的主要难点在于第三问该如何解决

于是就要知道BSGS是怎样的一种方法了

首先BSGS是meet in the middle的一种(戳下面看)

http://m.blog.csdn.net/blog/zentropy/11200099

看完链接后再看以下内容

---------------------------------------------------------------------------------------------------------------------

对于一个质数$p$我们由费马小定理知道$y^{x}mod p$最多$(p-1)$次便是一个循环节

因此如果有解$x$一定在$0$到$p-1$中

所以我们只需知道$x$取$0$到$p-1$是否有解即可

根据meet in the middle 的思想 令$m=\sqrt{p-1}$

那么我们仅需先求出 $x$为$0$到$m-1$的(如果有解这里就退出)

然后再求出 $x$为$m,2m,3m……nm(nm \leq p-1)$

分别询问$y^0$到$y^{m-1}$中是否有和$y^{km}$乘起来$=z(modp)$的

然而显然我们这个操作直接做的话 是$\sqrt{n}*\sqrt{n}=n$的

所以学过逆元怎么求了之后可以将$y^{km}(modp)$意义下的逆元与z相乘

然后再询问$y^0$到$y^{m-1}$中有没有与它相等的即可

这样去做就是$\sqrt{n}$*hash的复杂度

有手动hash技巧的话 hash复杂度可以看做1

比较懒的话 直接用map来hash就是$\log{(n)}$

#include <bits/stdc++.h>
using namespace std;
map<int,int> mp;
int solve1(int x,int y,int mod)
{
    long long t=x,re=1;
    while(y)
    {
        if(y&1)
            re=re*t%mod;
        t=t*t%mod;
        y>>=1;
    }
    return (int)re;
}
int exgcd(int a,int b,int &x,int &y)
{
    if(!b)
    {
        x=1;
        y=0;
        return a;
    }
    int t,d;
    d=exgcd(b,a%b,x,y);
    t=x;
    x=y;
    y=t-(a/b)*x;
    return d;   
}
void solve2(int y,int z,int p)
{
    int x,yy;
    int d=exgcd(y,p,x,yy);
    if(z%d)
    {
        puts("Orz, I cannot find x!");
        return;
    }
    x=(long long)x*(z/d)%p;
    x=(x<0?x+p:x);
    printf("%d\n",x);
}
bool solve3(int y,int z,int p)
{
//  if(z>=p)
//      return 0;
    y%=p;
    if(!y)
    {
        if(z)
            return 0;
        puts("1");
        return 1;
    }
    mp.clear();
    int m=ceil(sqrt(p-1));
    long long t=1;
    for(int i=0;i<m;++i)
    {
        if(t==z)
        {
            printf("%d\n",i);
            return 1;
        }
        if(!mp[t])
            mp[t]=i+1;
        else
            return 0;
        t=t*y%p;
    }
    int inv=solve1(y,p-1-m,p);
    t=z;
    for(int i=m;i<=p-2;i+=m)
    {
        t=t*inv%p;
        if(mp[t])
        {
            printf("%d\n",i+mp[t]-1);
            return 1;
        }
    }
    return 0;
}
int main()
{
    int t,ca,y,z,p;
    scanf("%d%d",&t,&ca);
    while(t--)
    {
        scanf("%d%d%d",&y,&z,&p);
        if(ca==1)
            printf("%d\n",solve1(y,z,p));
        else if(ca==2)
            solve2(y,z,p);
        else if(ca==3)
            if(!solve3(y,z,p))
                puts("Orz, I cannot find x!");
    }
    return 0;
}

 

posted @ 2015-08-30 18:30  sagitta  阅读(187)  评论(0编辑  收藏  举报