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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章