zoukankan      html  css  js  c++  java
  • 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
    ",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
    ",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
    ",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
    ",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;
    }
  • 相关阅读:
    压缩命令
    u盘挂载
    三种不同的空格
    打出圆圈数字①的快捷方法
    循环使用的一个坑
    Python&R:警告信息管理
    Matlab的基本矩阵运算
    R语言-程序执行时间
    Python:n个点的费马问题
    Python网络数据采集(1):博客访问量统计
  • 原文地址:https://www.cnblogs.com/sagitta/p/4771307.html
Copyright © 2011-2022 走看看