1. 程式人生 > >2815 Mod Tree 【高次不定方程 + 擴充套件 BSGS + 板子】

2815 Mod Tree 【高次不定方程 + 擴充套件 BSGS + 板子】

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 7143 Accepted Submission(s): 1750

Problem Description

這裡寫圖片描述
The picture indicates a tree, every node has 2 children.
The depth of the nodes whose color is blue is 3; the depth of the node whose color is pink is 0.
Now out problem is so easy, give you a tree that every nodes have K children, you are expected to calculate the minimize depth D so that the number of nodes whose depth is D equals to N after mod P.

Input

The input consists of several test cases.
Every cases have only three integers indicating K, P, N. (1<=K, P, N<=10^9)

Output

The minimize D.
If you can’t find such D, just output “Orz,I can’t find D!”

Sample Input

3 78992 453
4 1314520 65536
5 1234 67

Sample Output

Orz,I can’t find D!
8
20

題意: 一個樹上,每個節點有k個孩子,給你一個p和N ax%p==N,且不保證p為素數

分析: 這是一個板子題,如果p為素數的時候,是BSGS,這裡要用到擴充套件BSGS,原理看下這裡吧
就當做個板子吧

參考程式碼

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <map>
#include <cmath>
#include <unordered_map>

using namespace std
; typedef long long ll; unordered_map<ll,ll> ha; ll MOD; ll gcd(ll a, ll b) { return !b ? a : gcd(b, a % b); } #define mod(x) ((x) % MOD) ll qpow(ll a,ll b) { ll res = 1; while (b) { if (b & 1) { res = mod(res * a); } a = mod(a * a); b >>= 1; } return res; } ll ebsgs(ll a, ll b, ll p) { if (b == 1) return 0; ll t,d = 1,k = 0; while ((t = gcd(a, p)) != 1) { if (b % t) return -1; k++,b /= t,p /= t, d = (d*(a / t)) % p; if (b == d) return k; } ha.clear(); ll m = ceil(sqrt(p+0.5)); ll a_m = qpow(a,m); ll mul = b; for (ll j = 1; j <= m; j++) { mul = (mul * a) % p; ha[mul] = j; } for (ll i = 1; i <= m; i++) { d = (d * a_m) % p; if (ha[d]) return i * m - ha[d] + k; } return -1; } int main() { ll a,b; while (~scanf("%lld%lld%lld", &a, &MOD, &b)) { if (b >= MOD) { puts("Orz,I can’t find D!");continue; } if (ebsgs(mod(a), mod(b),MOD) == -1) puts("Orz,I can’t find D!"); else printf("%lld\n", ebsgs(mod(a), mod(b),MOD)); } return 0; }

手寫hash實現BSGS程式碼(僅記錄)


//程式碼不是擴充套件BSGS,是普通的BSGS
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cstdio>
#include<cmath>

#define ll long long
#define MEM(a,b) memset((a),(b),sizeof(a))

using namespace std;

const int N = 499991;

ll a,p,b;

bool Hash[N];
int val[N];
int id[N];

void Insert(int i,ll num){
    ll k = num%N;
    while(Hash[k] &&val[k] != num){k = (k+1)%N;}
    if(!Hash[k]){
        Hash[k] = true;
        val[k] = num;
        id[k] = i;
    }
}
void egcd(ll a,ll b,ll& d,ll& x,ll &y){
    if(!b){d = a,x = 1;y = 0;}
    else{egcd(b,a%b,d,y,x);y -= x*(a/b);}
}
int found(ll num){
    ll k = num%N;
    while(Hash[k] && val[k]!=num){k = (k+1)%N;}
    if(Hash[k])return id[k];
    return -1;
}
int BSGS(){
    MEM(Hash,false);
    MEM(val,-1);
    MEM(id,-1);
    ll m = ceil(sqrt(p));
    ll M = 1;
    for(int i = 0;i < m;i++){
        Insert(i,M);
        M = a*M%p;
    }
    ll t = 1;
    for(int i = 0;i < m;i++){
        ll x,y,d;
        egcd(t,p,d,x,y);
        x = x*b%p;
        x = (x+p)%p;
        int s = found(x);
        if(s != -1)return s+m*i;
        t = t*M%p;
    }
    return -1;
}
int main(){
    while(cin>>p>>a>>b){
        int ans = BSGS();
        if(ans == -1)cout<<"no solution"<<endl;
        else cout<<ans<<endl;
    }
    return 0;
}