最近《高等代数》刚学了域的概念,突然想起曾经这么的一个问题,找了许久才找到以前用的那种方法,觉得还是挺有启发性的。
那么问题就是给定正整数 (nge 2),需要构造一个 (n) 元有限域,也就是说我们给出一个 (n imes n) 的加法表和 (n imes n) 的乘法表。
不难得知,难点在于选择恰当的运算规则使得乘法逆存在。
Case 1
若 (n) 是质数,那么有如下构造 (mathbb{Z}_p=S={0,1,2,dots,p-1}):
- (forall a,bin S,aoplus b=a+b-[dfrac{a+b}{p}] imes p in S)
- (forall a,bin S,aotimes b=ab-[dfrac{ab}{p}] imes p in S)
根据费马小定理,乘法逆可以定义为 (a^{-1}=a^{p-2})。
Case 2
若 (n) 含有至少两个质因子。我们断言,这种情况下不存在 (n) 元的有限域。
Case 3
剩余的情况,则 (n=p^k),其中 (pin prime,kge 2)。
我们构造多项式
即构造一个定义系数在 (mathbb{Z}_p) 上的度数不超过 (p-1) 的多项式域 (G),而该域的大小恰好为 (p^k);
我们可以通过 (p) 进制分解(或其他方式)将 (S={0,1,2,dots,n-1}) 与 (G) 形成双射。
现在我们定义 (G) 的运算,考虑到需要保证其度数不超过 (p-1),我们先取一个系数在 (mathbb{Z}_p) 上的度数为 (p) 的不可约多项式 (M(x));
- (forall f(x),g(x)in G,f(x)oplus g(x)=f(x)+g(x) in S)
- (forall f(x),g(x)in G,r(x)=f(x)otimes g(x)=f(x)g(x)mod M(x)),即多项式的带余除法结果,(delta(r(x))<delta(M(x))=p),故 (r(x)in S)
与此同时,多项式 (I(x)=1) 即为乘法幺元。
由于 (M(x)) 是不可约多项式,可以证明任取一个 (G) 中的元素 (f),均存在一个 (gin G) 使 (f(x)otimes g(x) =I(x))。(存在多项式乘法逆)
需要注意,例如在 (mathbb{Z}_2) 上,(x^2+1) 并不是不可约多项式,因为 ((x+1)(x+1)=x^2+1);而 (x^2+x+1) 满足;在 (mathbb{Z}_3) 上,可取 (x^2+x+2) 为不可约多项式。
至此,我们完成了构造。
附1
实现上述得到的一个 (9) 元域(加法表 和 乘法表)
0 1 2 3 4 5 6 7 8
1 2 0 4 5 3 7 8 6
2 0 1 5 3 4 8 6 7
3 4 5 6 7 8 0 1 2
4 5 3 7 8 6 1 2 0
5 3 4 8 6 7 2 0 1
6 7 8 0 1 2 3 4 5
7 8 6 1 2 0 4 5 3
8 6 7 2 0 1 5 3 4
0 0 0 0 0 0 0 0 0
0 1 2 3 4 5 6 7 8
0 2 1 6 8 7 3 5 4
0 3 6 7 1 4 5 8 2
0 4 8 1 5 6 2 3 7
0 5 7 4 6 2 8 1 3
0 6 3 5 2 8 7 4 1
0 7 5 8 3 1 4 2 6
0 8 4 2 7 3 1 6 5
附2
参考代码(手动寻找不可约多项式,只能处理少数固定大小的 (n))
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
typedef vector<int> poly;
int n, p, k;
poly d, av;
vector<poly> a;
void dfs(int x)
{
if(x < 0)
{
a.emplace_back(av);
return;
}
for(int j = 0; j < p; ++j)
av[x] = j, dfs(x - 1);
}
int calc(const poly& a)
{
int res = 0;
for(int i = 0, q = 1; i < k; ++i)
res += a[i] * q, q = q * p;
return res;
}
poly operator + (const poly&a, const poly&b)
{
poly c = a;
for(int i = 0; i < k; ++i) c[i] = (a[i] + b[i]) % p;
return c;
}
poly operator * (const poly&a, const poly&b)
{
poly c(k + k - 1);
for(int i = 0; i < k; ++i)
for(int j = 0; j < k; ++j)
c[i + j] += a[i] * b[j];
for(int i = 2 * k - 2; i >= k; --i)
for(int j = 0; j < k; ++j)
c[i + j - k] -= c[i] * d[j];
for(int i = 0; i < k; ++i)
c[i] = (c[i] % p + p) % p;
c.resize(k);
return c;
}
int main()
{
freopen("1.out","w",stdout);
scanf("%d", &n);
for(int x = 2; x <= n; ++x)
if(n % x == 0)
{
p = x;
int y = n;
while(y % x == 0) y /= x, ++k;
if(y != 1)
return puts("-1"), 0;
break;
}
puts("0");
if(k == 1)
{
for(int x = 0; x < n; ++x)
for(int y = 0; y < n; ++y)
printf("%d%c", (x + y) % n, "
"[y + 1 == n]);
for(int x = 0; x < n; ++x)
for(int y = 0; y < n; ++y)
printf("%d%c", (x * y) % n, "
"[y + 1 == n]);
return 0;
}
if(k == 2)
{
if(p != 5 && p != 11)
d = poly{-1, 1, 1};
else
d = poly{1, 1, 1};
}
else if(k == 3)
{
if(p == 3)
d = poly{-1, 0, 1, 1};
else
d = poly{1, 1, 0, 1};
}
else if(k == 4)
d = poly{1, 1, 1, 1, 1};
else if(k == 5)
d = poly{1, 1, -1, -1, 0, 1};
else if(k == 7)
d = poly{1, 1, -1, -1, 0, 0, 0, 1};
else if(k == 8)
d = poly{1, 1, -1, 0, 0, 0, 0, -1, 1};
av = poly(k);
dfs(k - 1);
for(int x = 0; x < n; ++x)
for(int y = 0; y < n; ++y)
printf("%d%c", calc(a[x] + a[y]), "
"[y + 1 == n]);
for(int x = 0; x < n; ++x)
for(int y = 0; y < n; ++y)
printf("%d%c", calc(a[x] * a[y]), "
"[y + 1 == n]);
}