51nod 1038(n次剩余)

题目链接: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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
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;
    }
}
//扩展欧几里得算法
vectora;
bool g_text(long long g,long long p){
    for(long long i=0;iresidue(long long p,long long n,long long a){
    vectorret;
    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;ians;
        ans=residue(p,A,b);
        if(ans.empty()){
            puts("No Solution");
        }
        else {
            for(unsigned int i=0;i




你可能感兴趣的:(North--数论,North--同余,North--N次剩余,北门的智慧——数论,N次剩余)