题意:求满足a^x=b(mod n)的最小的整数x。

分析:很多地方写到n是素数的时候可以用Baby step,Giant step, 其实研究过Baby step,Giant step算法以后,你会发现  它能解决    “n与a互质”的情况,而并不是单纯的n是素数的情况。如果a与n不是互质的,那么我们需要处理一下原方程,让a与n互质,然后再用Baby step,Giant step解出x即可。

Baby step,Giant step算法思想:对于a与n互质,那么则有a^phi(n)=1(mod n),   对于n是素数phi(n) == n-1, 否则phi(n) < n-1, 所以x的取值只要在0----n-2之中取就可以了。

当n很小时,可以直接枚举,但当n很大时,肯定会超时,Baby step,Giant step就是用了一种O(sqrt(n)*log(n))的方法枚举了所有的0-----n-2。令m = sqrt(n);

我们可以预处理出a^0,a^1,.........a^m,都放入哈希表中, 然后  (a^m)^i+v(哈希表里的其中一个值)就一定是解,每次枚举i(0-----m-1),计算出v,判断v是否出现在哈希表中,如果有就是解。  对于m为什么取sqrt(n)是为了复杂度的平衡,这一点是跟分块算法很相似的。

对于a与n不互质的情况分析:令 t = gcd(a,n),那么a与n都约去t,当然b也要约去t(不能约去就无解),约去一个t以后方程就变为   aa*a^(x-1) = bb(mod nn), (其中  aa = a/t    bb = b/t    nn = n/t) , 这里nn还可能与a不互质,那么我们一直拿出一个新的a对(a, bb, nn)约去t,直到a与nnn....(nnn...表示约去若干次t以后的n)互质。以下用(用三个字母表示约去若干次后,如bbb) 则结果为aa^c*a^(x-c) = bbb(mod nnn),      我们让等式左右分别乘以aa^c关于nnn的逆元       变为a^(x-c) = w    (mod  nnn) ,    w =bbb *(aa^c)^(-1)。   a^x = w  (mod n)可以用bbb *(aa^c)^(-1)Baby step,Giant step直接求出,如果有解那把未知数+c。

具体看代码中的cal函数。

注意:在以上过程中x有可能<c,所以我们必须每约去一个t就要特判一下当前情况aa 与 bb就说明当前c是解。

哈希表实现看题目时间要求,map太慢,自己手写hash是很快的。

map哈希

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <map>
using namespace std;
typedef long long ll;
void ex_gcd(ll a, ll b, ll &x, ll &y) {
if (!b) {
x = 1;
y = 0;
} else {
ex_gcd(b, a % b, y, x);
y -= a / b * x;
}
}
inline ll inv(ll a, ll n) {
ll x, y;
ex_gcd(a, n, x, y);
return (x + n) % n;
}
ll log_mod(ll a, ll b, ll n) {
ll m, e;
int i;
m = sqrt(n + 0.5);
map<ll, ll> f;
f[1] = 0;
e = 1;
for (i = 1; i < m; i++) {
e = e * a % n;
if (!f.count(e))
f[e] = i;
}
e = e * a % n;
e = inv(e, n);
for (i = 0; i < m; i++) {
if (f.count(b))
return i * m + f[b];
b = b * e % n;
}
return -1;
}
ll gcd(ll a, ll b) {
return b ? gcd(b, a % b) : a;
}
ll cal(ll a, ll b, ll n) {
ll t, c = 0, v = 1;
while ((t = gcd(a, n)) != 1) {
if (b % t)
return -1;
n /= t;
v = v * a / t % n;
b /= t;
c++;
if (b == v)
return c;
}
//printf("a = %I64d b = %I64d c = %I64d v = %I64d\n", a, b, c, v);
b *= inv(v, n);
b %= n;
ll ret = log_mod(a, b, n);
return ~ret ? ret + c : ret;
}
int a, b, n;
int main() {
while (~scanf("%d%d%d", &a, &n, &b)) {
if (b >= n) {
printf("Orz,I can’t find D!\n");
continue;
}
if (b == 0) {
printf("0\n");
continue;
}
ll ans = cal(a, b, n);
if (ans == -1)
printf("Orz,I can’t find D!\n");
else
printf("%I64d\n", ans);
}
return 0;
}

手写hash

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <map>
using namespace std;
typedef long long ll;
const int maxn = 100007;
struct hash {
int n;
struct Edge {
int p, v;
int next;
}edge[maxn*7];
int head[maxn+10], E;
void init(int n) {
this->n = n;
memset(head, -1, sizeof(int)*(n+1));
}
void add(int p, int v) {
int s = p%n;
edge[E].p = p;
edge[E].v = v;
edge[E].next = head[s];
head[s] = E++;
}
int get(int p) {
int s = p%n;
for(int i = head[s]; ~i; i = edge[i].next) {
if(edge[i].p == p) return edge[i].v;
}
return -1;
} }f;
void ex_gcd(ll a, ll b, ll &x, ll &y) {
if (!b) {
x = 1;
y = 0;
} else {
ex_gcd(b, a % b, y, x);
y -= a / b * x;
}
}
inline ll inv(ll a, ll n) {
ll x, y;
ex_gcd(a, n, x, y);
if(x < 0) x += n;
return x;
}
ll log_mod(ll a, ll b, ll n) {
ll m, e;
int i;
m = sqrt(n + 0.5);
f.init(10007);
f.add(1, 0);
e = 1;
for (i = 1; i < m; i++) {
e = e * a % n;
if (f.get(e) == -1) f.add(e, i);
}
e = e * a % n;
e = inv(e, n);
for (i = 0; i < m; i++) {
int t = f.get(b);
if (~t)
return i * m + t;
b = b * e % n;
}
return -1;
}
ll gcd(ll a, ll b) {
return b ? gcd(b, a % b) : a;
}
ll cal(ll a, ll b, ll n) { //扩展函数
ll t, c = 0, v = 1;
while ((t = gcd(a, n)) != 1) {
if (b % t)
return -1;
n /= t;
b /= t;
v = v * a / t % n;
c++;
if (b == v) return c;
}
b = b*inv(v, n)%n;
ll ret = log_mod(a, b, n);
return ~ret ? ret + c : ret;
}
int a, b, n;
int main() {
while (~scanf("%d%d%d", &a, &n, &b)) {
if (b >= n) {
printf("Orz,I can’t find D!\n");
continue;
}
if (b == 0) {
printf("0\n");
continue;
}
ll ans = cal(a, b, n);
if (ans == -1)
printf("Orz,I can’t find D!\n");
else
printf("%I64d\n", ans);
}
return 0;
}

[置顶] hdu2815 扩展Baby step,Giant step入门的更多相关文章

  1. HDU 2815 扩展baby step giant step 算法

    题目大意就是求 a^x = b(mod c) 中的x 用一般的baby step giant step 算法会超时 这里参考的是http://hi.baidu.com/aekdycoin/item/2 ...

  2. 【学习笔记】Baby Step Giant Step算法及其扩展

    1. 引入 Baby Step Giant Step算法(简称BSGS),用于求解形如\(a^x\equiv b\pmod p\)(\(a,b,p\in \mathbb{N}\))的同余方程,即著名的 ...

  3. 解高次同余方程 (A^x=B(mod C),0<=x<C)Baby Step Giant Step算法

    先给出我所参考的两个链接: http://hi.baidu.com/aekdycoin/item/236937318413c680c2cf29d4 (AC神,数论帝  扩展Baby Step Gian ...

  4. HDU 2815 Mod Tree 离散对数 扩张Baby Step Giant Step算法

    联系:http://acm.hdu.edu.cn/showproblem.php?pid=2815 意甲冠军: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQ ...

  5. 『高次同余方程 Baby Step Giant Step算法』

    高次同余方程 一般来说,高次同余方程分\(a^x \equiv b(mod\ p)\)和\(x^a \equiv b(mod\ p)\)两种,其中后者的难度较大,本片博客仅将介绍第一类方程的解决方法. ...

  6. POJ 3243 Clever Y (求解高次同余方程A^x=B(mod C) Baby Step Giant Step算法)

    不理解Baby Step Giant Step算法,请戳: http://www.cnblogs.com/chenxiwenruo/p/3554885.html #include <iostre ...

  7. 数论之高次同余方程(Baby Step Giant Step + 拓展BSGS)

    什么叫高次同余方程?说白了就是解决这样一个问题: A^x=B(mod C),求最小的x值. baby step giant step算法 题目条件:C是素数(事实上,A与C互质就可以.为什么?在BSG ...

  8. 【POJ2417】baby step giant step

    最近在学习数论,然而发现之前学的baby step giant step又忘了,于是去翻了翻以前的代码,又复习了一下. 觉得总是忘记是因为没有彻底理解啊. 注意baby step giant step ...

  9. POJ 2417 Discrete Logging ( Baby step giant step )

    Discrete Logging Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 3696   Accepted: 1727 ...

随机推荐

  1. aliyun.com

    https://help.aliyun.com/knowledge_detail/39495.html?spm=5176.7839494.2.1.AhdvPM

  2. TCP连接状态详解及TIME_WAIT过多的解决方法

    上图对排除和定位网络或系统故障时大有帮助,但是怎样牢牢地将这张图刻在脑中呢?那么你就一定要对这张图的每一个状态,及转换的过程有深刻地认识,不能只停留在一知半解之中.下面对这张图的11种状态详细解释一下 ...

  3. gcc选项-g与-rdynamic的异同

    摘自http://www.tuicool.com/articles/EvIzUn gcc选项-g与-rdynamic的异同 gcc 的 -g ,应该没有人不知道它是一个调试选项,因此在一般需要进行程序 ...

  4. Android使用Google推荐的联网框架Volley,让连接网络更加简单

    大家好.随着技术的进步.科技的发达,非常少有应用是单机的了,大部分都须要联网訪问server,曾经我们都用 httpclient和httpurlconnection,感觉是不是非常麻烦,而Google ...

  5. 依赖注入及AOP简述(一)——“依赖”的概念 .

    一.入门:依赖注入 作为一种全新的设计模式理念,“依赖注入”这个词汇在软件设计开发中已经是越来越耳熟能详了,而各种流行于开源社区的“依赖注入框架”,也越来越多的被当作软件工程开发过程中使用的基础框架. ...

  6. EK中fromCharCode和parseInt的配合使用

    基于web的漏洞攻击的第一步一般是:在landing page中通过<script>标签下的JavaScript脚本引入一些恶意链接.这些脚本往往会採用各种各样的混淆.加密手法来躲避AV和 ...

  7. Sequence one(hdu2610dfs+去重)

    题目:有一个数列N,和一个数字k,输出该数列的前k个子序列,如果k大于N的所有子序列,输出所有符合要求的序列,序列要求不能是递减序列 比如: 3 5 1 3 2 的前五个序列为 1 3 2 1 3 1 ...

  8. JQuery中html()方法的注意事项

    .html方法当不传参数时用来获取元素的html内容, return this[0] && this[0].nodeType === 1 ? this[0].innerHTML.rep ...

  9. Bctf-pwn_ruin-re_lastflower

    Pwn-ruin 用几个词来概括下漏洞原理:Arm+heap overflow(house of force)+dl-resolve Info leak: 在printf key8时,泄漏堆上地址(s ...

  10. 图像、帧、片、NALU概念理解

    图像.帧.片.NALU 是学习 H.264 的人常常感到困惑的一些概念. H.264 是一次概念的革新,它打破常规,完全没有 I 帧.P帧.B 帧的概念,也没有 IDR 帧的概念.对于 H.264 中 ...