1. 程式人生 > >離散對數-BSGS演算法

離散對數-BSGS演算法

口胡

離散對數主要是求解這樣一類問題:

axb(modm)a^x \equiv b \pmod m 大概就是(modm)\pmod m意義下的對數

這裡只考慮 (m,a)(m,a)為1的情況。一般來說,給出的m是一個質數。

x=Ap+Bx = A \lceil \sqrt{p} \rceil + B,其中 0B<p0 \leq B < \lceil \sqrt{p} \rceil0A<p0 \leq A < \lceil \sqrt{p} \rceil

。則方程變成

aAp+Bb(modp)a^{A\lceil \sqrt{p} \rceil + B} \equiv b \pmod p
兩邊同時乘以ApA \lceil \sqrt{p} \rceil的逆元,則方程變為
aBbaAp(modp)a^{B} \equiv b\cdot a^{-A\lceil \sqrt{p} \rceil} \pmod p
由於AA,BB都是O(p)O(\sqrt{p})級別的數,可以預處理出左邊的所有值,然後按從小到大的順序列舉A

A,查詢左邊是否有值對應。採用手寫hashhash或者C++11的unorderedunordered_mapmap就可以O(1)O(1)時間查詢。這樣的複雜度是O(p+p)O(\sqrt{p} + \sqrt{p})的。

如果需要對nnbb求解這個模方程,考慮將xx 表示為AK+BA*K + B,則 ApkA \leq \lfloor \frac{p}{k}\rfloor,預處理左邊之後,只需要在右邊重複查詢nn次即可。時間複雜度為 O(K+pkn)O(K + \lfloor \frac{p}{k}\rfloor * n)

code:

對於xy=nmod  mx^y = n \mod m 求解yy

LL discrete_log(int x,int _n,int m){
	unordered_map<LL,int>rec;
	int s=(int)(sqrt((double)m));
	for(; (LL)s*s<=m;)++s;
	LL cur=1;
	for(int i=0;i<s;++i){
		rec[cur]=i;
//		cur=cur*x%m;
		MUL(cur,x,m);
	}
	LL mul=cur;
	cur=1;
	for(int i=0;i<s;++i){
		LL more=(LL)_n;
		MUL(more,qpow(cur,m-2,m),m);
		if(rec.count(more)){
			return i*s +rec[more];
		}
//		cur= cur*mul%m;
		MUL(cur,mul,m);
	}
	return -1;
}
#include<bits/stdc++.h>

using namespace std;

#define lson rt<<1
#define rson rt<<1|1

typedef long long ll;
const int mod = 1e9+7;
const int _mod = mod - 1;
const int _P = 5;
const int maxn = 1e5+10;

ll a[maxn],Log[maxn];

struct node{
    int l,r;
    ll sum,add,mul;
}tr[maxn<<2];

void Add(ll& x,ll y,int P){
    x+=y;
    if(x>=P) x -= P;
}

void Mul(ll& x,ll y,int P){
    x *= y;
    if(x>=P) x %= P;
}

ll qpow(ll a,ll b,ll P){
    ll ret = 1;
    while(b){
        if(b&1) Mul(ret,a,P);
        Mul(a,a,P);
        b>>=1;
    }
    return ret;
}

void up(int rt){
    tr[rt].sum = tr[lson].sum + tr[rson].sum;
    if(tr[rt].sum >= _mod) tr[rt].sum -= _mod;
}

void down(int rt){
    int m = (tr[rt].l + tr[rt].r)>>1;
    // cout<<"down "<<rt<<' '<<tr[rt].l<<' '<<tr[rt].r<<endl;
    // cout<<tr[rt].mul<<' '<<tr[rt].add<<endl;
    if(tr[rt].mul > 1){
        int c = tr[rt].mul;
        Mul(tr[lson].mul,c,_mod);
        Mul(tr[rson].mul,c,_mod);
        Mul(tr[lson].sum,c,_mod);
        Mul(tr[rson].sum,c,_mod);
        Mul(tr[lson].add,c,_mod);
        Mul(tr[rson].add,c,_mod);
        tr[rt].mul = 1;
    }
    if(tr[rt].add > 0){
        int c = tr[rt].add;
        Add(tr[lson].add,c,_mod);
        Add(tr[rson].add,c,_mod);
        Add(tr[lson].sum,(ll)(m-tr[rt].l + 1) * c % _mod,_mod);
        Add(tr[rson].sum,(ll)(tr[rt].r - m) * c % _mod,_mod);
        tr[rt].add = 0;
    } 
}

void build(int rt,int L,int R){
    // cout<<rt<<' '<<L<<' '<<R<<endl;
    tr[rt].l = L;
    tr[rt].r = R; 
    tr[rt].add = 0;
    tr[rt].mul = 1;
    if(L == R){
        tr[rt].sum = a[L];
        return ;
    }
    int m = (L+R)>>1;
    build(lson,L,m);
    build(rson,m+1,R);
    up(rt);
}

void update(int rt,int L,int R,int v,int k){
    if(L <= tr[rt].l && tr[rt].r <= R){
        if(k == 1){            
            Add(tr[rt].sum,(ll)(tr[rt].r - tr[rt].l + 1) * v % _mod,_mod);
            Add(tr[rt].add,v,_mod);
        }
        else{
            Mul(tr[rt].sum,v,_mod);
            Mul(tr[rt].mul,v,_mod);
            Mul(tr[rt].add,v,_mod);
        }
        return ;
    }
    down(rt);
    int m = (tr[rt].l + tr[rt].r) >> 1;
    if(L <= m) update(lson,L,R,v,k);
    if(m < R) update(rson,L,R,v,k);
    up(rt);
}

ll query(int rt,int L,int R){
    // cout<<"query "<<rt<<' '<<tr[rt].l<<' '<<tr[rt].r<<' '<<L<<' '<<R<<endl;
    if(L <= tr[rt].l && tr[rt].r <= R) return tr[rt].sum;
    down(rt);
    int m = (tr[rt].l + tr[rt].r) >> 1;
    ll ret = 0;
    if(L <= m) Add(ret,query(lson,L,R),_mod);
    if(m < R) Add(ret,query(rson,L,R),_mod);
    return ret;
}

const int K = 300000;
unordered_map<ll,int> rec;
ll Base;

ll get_log(int x,int _n,int m){
	ll mul = Base;
	ll cur=1;
	for(int i=0;i<K;++i){
		ll more=(ll)_n;
		Mul(more,qpow(cur,m-2,m),m);
		if(rec.count(more)){
			return i*K + rec[more];
		}
		Mul(cur,mul,m);
	}
	return -1;
}

bool check[2005];

void init(){
    memset(check,false,sizeof(check));
	ll cur = 1;
	for(int i = 0;i<K;i++){
		rec[cur] = i;
		Mul(cur,_P,mod);
	}
	Base = cur;
    Log[1] = get_log(_P,1,mod);
    for(int i = 2;i< 1005;i++){
        if(!check[i]){
            Log[i] = get_log(_P,i,mod) % _mod;
        }
        for(int j = i * 2; j < 1005;j += i){
            check[j] = true;
            Log[j] = Log[j/i] + Log[i];
            if(Log[j] >= _mod) Log[j] -= _mod;
        }
    }
}

int main(){
    init();
    int cas; scanf("%d",&cas);
    while(cas--){
        int n,q;
        scanf("%d%d",&n,&q);
        for(int i = 1;i<=n;i++
            
           

相關推薦

離散對數-BSGS演算法

口胡 離散對數主要是求解這樣一類問題: ax≡b(modm)a^x \equiv b \pmod max≡b(modm) 大概就是(modm)\pmod m(modm)意義下的對數 這裡只考慮 (m,a)(m,a)(m,a)為1的情況。一般來說,給出的m是一個

求解離散對數——BSGS演算法の板子

BSGS這玩意兒好像用的不是很多?好像除了POJ和HDU有兩道題,然後就是SDOI的兩個題了。。然後關於這玩意兒正確性的很多證明ATP都不是很懂。。這裡只是解釋一下它的實現過程。。 BSGS BSGS演算法(Baby Step Gaint Ste

BSGS離散對數(Baby-Step-Giant-Step)

blog 常數 離散 自然 處理 sqrt 插入 如果 枚舉 BSGS離散對數(Baby-Step-Giant-Step) 題目: 給定\(x,y,p,\)求最小的自然數\(k\)滿足\(x^k=y(\mod p)\)\(p\le2^{31}\)(滿足一定有答案) 題解:

擴充套件BSGS求解離散對數問題

擴充套件BSGS用於求解axΞb mod(n) 同餘方程中gcd(a,n)≠1的情況 基本思路,將原方程轉化為a與n互質的情況後再套用普通的BSGS求解即可 struct Hashmap{ static const int Ha=999917,maxe=46340; int E,ln

密碼學之Pohlig-Helliman演算法離散對數

對於一個素數p,先求n=p-1並將其分解為x個素數因子,對於每一個因子q及其指數c,應用Pohlig-Helliman演算法求解(a0,a1,a3............ac-1) 根據a=(for i=0 to c-1:ai*q^i)+s*q^(s為某一整數) 求得  x

BSGS+原根+離散對數

前提知識:尤拉定理 這個東西有點強啊。 離散對數就是求給定a,b,p 讓你求 a^x ≡b mod(p) 意義下的 這個x。 這個東西我們用BSGS演算法有點牛逼的名字(拔山蓋世,北上廣深) 我們令x=i*c+j , c=ceil(sqrt(p))

BZOJ 3992: [SDOI2015]序列統計 快速冪+NTT(離散對數下)

不同 led gre lan cnblogs 至少 inf tro 程序編寫 3992: [SDOI2015]序列統計 Description 小C有一個集合S,裏面的元素都是小於M的非負整數。他用程序編寫了一個數列生成器,可以生成一個長度為N的數列,數列中

離散對數二連 poj 2417 Discrete Logging & HDU 2815 Mod Tree

tdi close efi 信息 euc xtend spl insert key 題目就不貼了。都是一樣的套路求解a^x % c = b的最小x 註意HDU的題目很坑,有b比c大和題目中輸出信息為全角引號的坑 下面貼的是HDU的版本,poj的改一下a,b,c順序和輸出就好

【Ex_BSGS&BSGS演算法模板】poj2417 poj3243

題意:給定a,b,p,求最小的非負整數x,滿足  ax ≡ b(mod p) Ex_BSGS,p是不是素數都可以 //#include <bits/stdc++.h> ///複雜度為O(sqrt(n)) #include &l

【科技】原根的快速判斷方法以及對1求離散對數的另一種想法

鑑於實際需要,本文中所選的模數$p$總是一個平凡質數,並用$\phi$表示$\phi (p) = p - 1$。 原根的定義: 基於$p$是質數,我們可以很簡單的把它的定義想成,如果一個數$a \in [0, p - 1]$是原根的充要條件是對於$x \in [0, p - 2]$,$a^{x}$互不相同

DCT(離散餘弦變換)演算法原理和原始碼(python)

  原理:   離散餘弦變換(DCT for Discrete Cosine Transform)是與傅立葉變換相關的一種變換,它類似於離散傅立葉變換(DFT for Discrete Fourier Transform),但是隻使用實數。離散餘弦變換相當於一個長度大概是它兩倍的離散傅立葉變換,這個離散傅立

POJ 2417 Discrete Logging [BSGS演算法]

POJ 2417 Discrete Logging Description Given a prime P, 2 <= P < 231, an integer B, 2 <= B < P, and an integer N, 1 &l

POJ-3243-Clever Y-擴充套件Bsgs演算法-已知a,c,p,和a^b=c(mod p),求b

【Description】 Little Y finds there is a very interesting formula in mathematics: XYmod&MediumSpace;Z=K X^Y mod\:Z=K XYmodZ=K

離散對數 && EXBSGS】Gym

Step1 Problem: a^x ≡ b(mod m). 給你 a, b, m, 求 x. 資料範圍: 1<=T<=500, 0 <= a, b < m <= 1e9. Step2 Ideas: 學習演算法部落格 說說自己

離散對數概念

2018-06-27 概念 同餘運算 數學上,同餘(congruence modulo,符號:$\equiv$)是數論中的一種等價關係。當兩個整數除以同一個正整數,若得相同餘數,則二整數同餘。同餘是抽象代數中的同餘關係的原型。最

中科院NIPS 2017論文提出深度離散雜湊演算法,可用於影象檢索:Deep Supervised Discrete Hashing

  中國科學院 提出了一種深度離散雜湊演算法(discrete hashing algorithm),該演算法認為學習到的二值編碼應該也可以用於分類。 實驗結果表明該方法在基準資料集上的表現要好過目前最好的雜湊方法。 圖 1 深度離散雜湊編碼示意圖 由於網路上的影象和視訊

離散對數和橢圓曲線加密原理

序言 現代公鑰加密系統中,常用的加密演算法除了RSA還有離散對數加密和橢圓曲線加密。這兩者原理比較相似,在這裡一併介紹。 離散對數問題 我們在中學裡學的對數問題是指, 給定正實數aa和axax,求xx。也就是計算x=logaaxx=lo

【PSO】離散粒子群演算法(DPSO)和離散二進位制粒子群演算法(BPSO )

1. 什麼是離散粒子群演算法?普通粒子群演算法(Particle Swarm Optimization Algorithm,PSO)的粒子初始位置、更新速度都是連續函式,與之對應,位置和速度更新均為離散

離散型遺傳演算法求解組合優化matlab實現

問題描述: 103個50維的節點中,選出n個節點進行組合,使其獲得較好的適應度值注意點:首先在原始資料檔案(txt)中,將相應的節點進行編號,編成1-103,放在第一列,之後再將編號對映到相應的真實節點上。需要資料檔案的小夥伴,可以到:https://download.csd

離散對數:這個好難

定義 設g是m的一個原根,對於滿足(k, m) = 1 的k, k關於g的離散對數(mod m)定義為一整數t,使gt≡k(modm) 且t為一個最小剩餘(modϕ(m))。 記作i