51nod 1038(n次剩余)

来源:互联网 发布:淘宝坑产是什么意思 编辑:程序博客网 时间:2024/06/06 05:56

题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1038;

题目分析:

1、原根:原根的分布比较广,最小原根通常也较小,可以枚举正整数来快速找原根,对于一个代检查的p,对p-1的每一个素因子a,检查,若成立则说明g不是原根。

2、离散对数 :给定的x,n,m 求的解(其中m是素数)。令s=,则有,即有。将所有的放入有序表中,从小到大枚举b,得到

看曾未知数解模线性方程。若解能在有序表中找到,则停止枚举,此时

3:N次剩余:给定N,a,p,求出在模p意义下的所有解(其中p是素数)。

令g为p的原根,因为p为素数,则,所以找到原根g就可以将{1,2,…,p-1}的数与{}建立一一对应关系。

,则有:

因为p是素数,所以方程左右都不可以为0。这样就可以将这p-1个取值与指数建立对应关系。原问题转换为:

对于y解模线性方程就可以解决。而则可以用解离散对数的方法求出。

代码如下:

#include <map>#include <math.h>#include <vector>#include <stdio.h>#include <string.h>#include <iostream>#include <algorithm>#include <functional>using namespace std;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次剩余int main(){    int t;    scanf("%d",&t);    while(t--){        long long p,A,b;        a.clear();        scanf("%I64d%I64d%I64d",&p,&A,&b);        vector<long long>ans;        ans=residue(p,A,b);        if(ans.empty()){            puts("No Solution");        }        else {            for(unsigned int i=0;i<ans.size();i++){                printf("%I64d ",ans[i]);            }            puts("");        }    }    return 0;}




0 0
原创粉丝点击