BSGS算法学习

嗯哼大步小步法。

一个非常暴力的想法.

注意到如果设C = ⌈√P⌉,那么任何一个数都可以写

成a1 * C + b1的形式,其中a1, b1 都< C.

那么预处理出A^i*C的值.然后在询问时枚举b1.

A^a1*C-b1 = B,A^a1*C = B * A^b1.

把A^b1乘一下,再去hash表里查找是否有对应的值即可.

复杂度为O(√P)

//POJ 2417

 1 #include<cstdlib>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<iostream>
 6 #include<map>
 7 #include<cmath>
 8 using namespace std;
 9 typedef long long ll;
10 map<ll,int>mmp;
11 int qmod(ll a,ll b,ll p)
12 {
13     ll ans=1;
14     while(b)
15     {
16         if(b&1)ans=ans*a%p;
17         a=a*a%p;b>>=1;
18     }
19     return ans;
20 }
21 int main()
22 {
23     ll p,a,b;
24     while(~scanf("%lld%lld%lld",&p,&a,&b))
25     {
26         mmp.clear();
27         if(a%p==0)
28         {
29             puts("no solution");
30             continue;
31         }
32         bool flag=0;
33         ll ans=0;
34         int c=ceil(sqrt(p));
35         for(int i=0;i<=c;++i)
36         {
37             if(i==0)
38             {
39                 ans=b%p;mmp[ans]=i;continue;
40             }
41             ans=ans*a%p;
42             mmp[ans]=i;
43         }
44         ll tmp=qmod(a,c,p);ans=1;
45         for(int i=1;i<=c;++i)
46         {
47             ans=ans*tmp%p;
48             if(mmp[ans])
49             {
50                 tmp=i*c-mmp[ans];
51                 printf("%d\n",(tmp%p+p)%p);
52                 flag=1;
53                 break;
54             }
55         }
56         if(!flag)puts("no solution");
57     }
58     return 0;
59 }

原文地址:https://www.cnblogs.com/nbwzyzngyl/p/8478115.html

时间: 2024-10-14 06:32:34

BSGS算法学习的相关文章

BSGS算法学习小记(大步小步算法)

简介 先看一个式子xy≡z(modp),z是质数 现在只知道x和z,要求y. 大步小步算法(BSGS,Baby Steps Giant Steps)就是解决这个问题. 算法流程 暴搜的枚举范围 根据费马小定理:xz?1≡1. 如果y已经枚举到了z-1了,继续枚举的话就会产生循环. 所以,在暴搜中y的枚举范围就是0--z-1. 如何优化暴搜 我们想一想可不可以用分块来解决枚举的y. 把y分成p?1????√分别枚举行不行? 设m=p?1????√,y=a?m+b,这样枚举a和b就相当于分块枚举了.

bzoj2242: [SDOI2011]计算器 &amp;&amp; BSGS 算法

BSGS算法 给定y.z.p,计算满足yx mod p=z的最小非负整数x.p为质数(没法写数学公式,以下内容用心去感受吧) 设 x = i*m + j. 则 y^(j)≡z?y^(-i*m)) (mod p) 则 y^(j)≡z?ine(y^(i*m)) (mod p)(逆元) 由费马小定理y^(p-1)≡1 (mod p) 得 ine(y^m) = y^(p-m-1)  ine(y^(i*m)≡ine(y^((i?1)m))?y^(p-m-1)  1.首先枚举同余符号左面,用一个hash保存

算法学习 - 表达树的建立(后缀表达式法),树的先序遍历,中序遍历,后序遍历

表达树就是根据后缀表达式来建立一个二叉树. 这个二叉树的每个叶子节点就是数,真祖先都是操作符. 通过栈来建立的,所以这里也会有很多栈的操作. 树的先序遍历,中序遍历,后序遍历的概念我就不讲了,不会的自行百度,不然也看不懂我的代码. 下面是代码: // // main.cpp // expressionTree // // Created by Alps on 14-7-29. // Copyright (c) 2014年 chen. All rights reserved. // #includ

我的算法学习之路

关于 严格来说,本文题目应该是我的数据结构和算法学习之路,但这个写法实在太绕口--况且CS中的算法往往暗指数据结构和算法(例如算法导论指的实际上是数据结构和算法导论),所以我认为本文题目是合理的. 这篇文章讲了什么? 我这些年学习数据结构和算法的总结. 一些不错的算法书籍和教程. 算法的重要性. 初学 第一次接触数据结构是在大二下学期的数据结构课程.然而这门课程并没有让我入门--当时自己正忙于倒卖各种MP3和耳机,对于这些课程根本就不屑一顾--反正最后考试划个重点也能过,于是这门整个计算机专业本

算法学习三阶段

?? 第一阶段:练经典经常使用算法,以下的每一个算法给我打上十到二十遍,同一时候自己精简代码, 由于太经常使用,所以要练到写时不用想,10-15分钟内打完,甚至关掉显示器都能够把程序打 出来. 1.最短路(Floyd.Dijstra,BellmanFord) 2.最小生成树(先写个prim,kruscal 要用并查集,不好写) 3.大数(高精度)加减乘除 4.二分查找. (代码可在五行以内) 5.叉乘.判线段相交.然后写个凸包. 6.BFS.DFS,同一时候熟练hash 表(要熟,要灵活,代码要

周总结(2017.2.16):第一周算法学习。

周总结:算法学习总结之DFS和BFS 一:DFS算法 目的:达到被搜索结构的叶节点. 定义:假定给定图G的初态是所有的定点都没有访问过,在G中任选一定点V为初始出发点,首先访问出发点并标记,然后依次从V出发搜索V的每个相邻点W,若W未曾出现过,则对W进行深度优先遍历(DFS),知道所有和V有路径相通的定点被访问. 如果从V0开始寻找一条长度为4的路径的话: 思路步骤: 先寻找V0的所有相邻点:dis{v1,v2,v3},V1没有访问过,所以对V1进行深度遍历并将V1标记为访问过,此时路径长度为1

算法学习 - 01背包问题(动态规划C++)

动态规划 01背包 问题描述 求解思路 代码实现 放入哪些物品 代码 动态规划 我在上一篇博客里已经讲了一点动态规划了,传送门:算法学习 - 动态规划(DP问题)(C++) 这里说一下,遇到动态规划应该如何去想,才能找到解决办法. 最主要的其实是要找状态转移的方程,例如上一篇博客里面,找的就是当前两条生产线的第i个station的最短时间和上一时刻的时间关系. minTime(station[1][i]) = minTime(station[1][i-1] + time[i], station[

LCA 算法学习 (最近公共祖先)poj 1330

poj1330 在求解最近公共祖先为问题上,用到的是Tarjan的思想,从根结点开始形成一棵深搜树,处理技巧就是在回溯到结点u的时候,u的子树已经遍历,这时候才把u结点放入合并集合中,这样u结点和所有u的子树中的结点的最近公共祖先就是u了,u和还未遍历的所有u的兄弟结点及子树中的最近公共祖先就是u的父亲结点.这样我们在对树深度遍历的时候就很自然的将树中的结点分成若干的集合,两个集合中的所属不同集合的任意一对顶点的公共祖先都是相同的,也就是说这两个集合的最近公共祖先只有一个.时间复杂度为O(n+q

算法学习 - 链表的游标实现~ C++

链表的游标实现,就是用另外一种方法来访问链表,模拟游标. 在我学习的理解中,就是创建一个节点数组,模拟内存的排列,然后从其中来申请内存和释放内存.但是实际的内存没有被释放~ 下面直接贴代码了: // // main.cpp // CursorList // // Created by Alps on 14-7-27. // Copyright (c) 2014年 chen. All rights reserved. // #include <iostream> #define CursorSp