N次剩餘模版

公式:xnamod  px^n \equiv a \mod p

long long quick_mod(long long a,long long b,long long mod){
    long long ans=1;
    while(b){
        if(b&1)ans=ans*a%mod;
        b>>=1;
        a=a*a%mod;
    }
    return ans;
}
//快速冪
long long ex_gcd(long long a, long long b, long long &x, long long &y) {
    if (b == 0) {
        x = 1, y = 0;
        return a;
    }
    else {
        long long r = ex_gcd(b, a % b, y, x);
        y -= x * (a / b);
        return r;
    }
}
//擴展歐幾里得算法
vector<long long>a;
bool g_text(long long g,long long p){
    for(long long i=0;i<a.size();i++)
        if(quick_mod(g,(p-1)/a[i],p)==1)
            return 0;
    return 1;
}
long long primitive_root(long long p){
    long long tmp=p-1;
    for(long long i=2;i<=tmp/i;i++){
        if(tmp%i==0){
            a.push_back(i);
            while(tmp%i==0)tmp/=i;
        }
    }
    if(tmp!=1)a.push_back(tmp);
    long long g=1;
    while(true){
        if(g_text(g,p))
            return g;
        ++g;
    }
}
//求解原根
struct sa{
    long long x;
    int id;
    bool operator<(const sa &b)const{
        if (x == b.x) return id < b.id;
        return x<b.x;
    }
}rec[100500];
//用rec存離散對數
long long discerte_log(long long x,long long n,long long m){
    int s=(int)(sqrt((double)m+0.5));
    while((long long)s*s<=m)s++;
    long long cur=1;
    sa tmp;
    for(int i=0;i<s;i++){
        tmp.x=cur,tmp.id=i;
        rec[i]=tmp;
        cur=cur*x%m;
    }
    sort(rec,rec+s);
    //這裏不能用map查找比較慢,採用排序二分就快了
    long long mul= quick_mod(cur, m - 2, m) % m;
    //這裏有的方法是在下面的循環裏求解快速冪,但本題是不行的  要在循環外面弄,保證時間
    cur=1;
    
    for(long long i=0;i<s;i++){
        long long more=n*cur%m;
        tmp.x=more,tmp.id=-1;
        int j=lower_bound(rec,rec+s,tmp)-rec;
        if(rec[j].x==more){
            return i*s+rec[j].id;
        }
        cur=cur*mul%m;
    }
    return -1;
}
//求解離散對數
vector<long long>residue(long long p,long long n,long long a){
    vector<long long>ret;
    if(a==0){
        ret.push_back(0);
        return ret;
    }
    long long g=primitive_root(p);
    long long m=discerte_log(g,a,p);
    if(m==-1)return ret;
    long long A=n,B=p-1,C=m,x,y;
    long long G=ex_gcd(A,B,x,y);
    if(C%G!=0)return ret;
    x=x*(C/G)%B;
    long long delta=B/G;
    for(int i=0;i<G;i++){
        x=((x+delta)%B+B)%B;
        ret.push_back(quick_mod(g,x,p));
    }
    sort(ret.begin(),ret.end());
    ret.erase(unique(ret.begin(),ret.end()),ret.end());
    return ret;
}  
//求解n次剩餘

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章