今天原本是學習離散對數第三類問題,也是最複雜的一類,不過容量太大,幾乎是之前所有知識的綜合了,所以先發一個重要步驟:解原根。
當考慮問題 時,兩邊取離散對數,底數需要取a的原根。原根有很多定義,這裏不詳講。求原根主要還是搜索,不過由beizer定理有一個優化:
如果不存在 使得 ,其中 是 即歐拉函數的質因子,那麼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;
}