2月28日 解原根(素数)

今天原本是学习离散对数第三类问题,也是最复杂的一类,不过容量太大,几乎是之前所有知识的综合了,所以先发一个重要步骤:解原根。
当考虑问题xab(modp) 时,两边取离散对数,底数需要取a的原根。原根有很多定义,这里不详讲。求原根主要还是搜索,不过由beizer定理有一个优化:
如果不存在pi 使得mϕ(p)pi1(modp) ,其中piϕ(p) 即欧拉函数的质因子,那么m是p的一个原根。一般我们求最小原根。
简单写了一段代码,但只适用素数,合数的过几天再写。

#include<cstdio>
#include<algorithm>
#include<cmath>
typedef long long ll;
#define MAXN 1000000
ll solu[MAXN];
ll solunum;
ll notpri[MAXN], pri[MAXN];
ll cnt = 0;
ll fast_pow(ll a, ll b, ll p)
{
    a %= p;
    ll tmp = 1;
    while (b)
    {
        if (b & 1)tmp = (tmp*a) % p;
        b >>= 1;
        a = (a*a) % p;
    }
    return tmp;
}
ll inv(ll a, ll p)
{
    return fast_pow(a, p - 2, p);
}
//素数初始化
void ini()
{
    pri[0] = 2;
    for (ll i = 2; i <= MAXN; i++)
    {
        if (!notpri[i])pri[cnt++] = i;
        for (ll j = 0; j < cnt; j++)
        {
            if (i*pri[j] >= MAXN)break;
            notpri[i*pri[j]] = 1;
        }
    }
}
ll proottable[MAXN];
ll factor[MAXN];//注意memset
ll factornum;
ll proot(ll n)
{
    memset(factor, 0, sizeof(factor));
    factornum = 0;
    ll ncopy = n;
    for (ll i = 0; i < cnt; i++)
    {
        ll flg = 0;
        if (pri[i] > n)break;
        ll m = pri[i];
        while (!(ncopy%m))
        {
            flg = 1;
            ncopy /= m;
        }
        if (flg)factor[factornum++] = pri[i];
        if (ncopy == 1)break;
        //if (ncopy / pri[i] < pri[i])
        //{
        //fac[factornum++] = pri[i];
        //break;
        //}
    }
    for (ll i = 2; i < n; i++)
    {
        ll flg = 1;
        for (ll j = 0; j < factornum; j++)
        {
            ll x = factor[j];
            ll yu = fast_pow(i, (n - 1) / factor[j], n);
            if (yu == 1)
            {
                flg = 0;
                break;
            }
        }
        if (flg == 1)return i;
    }
}
int main()
{
    ini();
    ll g;
    scanf("%lld", &g);
    printf("%lld", proot(g - 1));
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章