[luogu 3923]. 大学数学题

题意

构造一个\(n\)元有限域,若不存在输出-1,否则域中元素分别用\(0, 1, 2, \ldots, n - 1\)表示,输出加法表和乘法表。
\(n \leq 343\)

题解

我真的会域扩张吗?答:不会
首先,根据一些基础知识,有解当且仅当\(n = p ^ d\),其中\(p \in \mathbb{P}\)
其次,根据域扩张的知识,我们要构造的\(\text{GF}(p ^ d)\)一定是由素域\(\text{GF}(p)\)有限扩张而来的。
考察在\(\text{GF}(p)\)下的代数扩张,即假设存在一个\(\text{GF}(p)[[x]]\)下的不可约多项式\(f(x)\),设\(\zeta\)是这个多项式的一个根,那么\(\text{GF}(p ^ d)\)中的所有元素可以唯一表示成一个多项式

\[a_0 + a_1 \zeta + a_2 {\zeta} ^ 2 + \ldots + a_{d - 1} {\zeta} ^ {d - 1} \ (a_i \in \text{GF}(p)) \]

(实际上是基\(1, \zeta, {\zeta} ^ 2, \ldots, {\zeta} ^ {d - 1}\)的线性组合)
假设我们最后要输出的是这些多项式的加法表和乘法表,那么问题就转化为了找到一个合适的加法运算和乘法运算。
加法就是在域\(\text{GF}(p)[[x]]\)下的多项式加法,乘法就是在域\(\text{GF}(p)[[x]]\)下的多项式乘法。
但是多项式乘法会导致使用的基的大小变大,我们需要把基的大小缩到\(d\)
考虑可以应用线性组合\(f(\zeta) = 0\)
对于一个多项式,加上或减去\(k\)倍的\(f(\zeta)\)\(k \in \text{GF}(p)[[x]]\)),代入\(\zeta\)求值不变。
那么对于一个多项式,如果次数超过了\(d - 1\),可以将它对\(f(\zeta)\)取模,得到的结果是一个次数小于等于\(d - 1\)的多项式(即基的大小缩到了\(d\)),并且代入\(\zeta\)后值和原多项式值相等。
现在考虑的是我们输出的是一个数表而不是多项式表,考虑到要把多项式\(F\)映射到数\(f\),并且要求这个映射可逆。
如果有办法可以把\(\zeta\)搞出来,那么当然可以直接将\(F\)映射到\(F(\zeta)\)上,这是个同构映射,显然可逆。
但是求\(\zeta\)是不现实的,我们退而求其次,找一个要求不太高的可逆映射即可,比如把多项式\(F\)的系数看做数\(f\)\(p\)进制下每一位的值,可以验证这是可行的。
复杂度\(\mathcal O(n ^ 2 {\log} ^ 2 n)\)

#include <bits/stdc++.h>
using namespace std;
typedef vector <int> poly;
const int N = 360, M = 10;
const int R[7][8] = {
{1, 7, 11, 19, 37, 67, 131, 283}, // 2, 4, 8, 16, 32, 64, 128, 256
{1, 10, 34, 86, 250, -1, -1, -1}, // 3, 9, 27, 81, 243
{1, 27, 131, -1, -1, -1, -1, -1}, // 5, 25, 125
{1, 50, 345, -1, -1, -1, -1, -1}, // 7, 49, 343
{1, 122, -1, -1, -1, -1, -1, -1}, // 11, 121
{1, 171, -1, -1, -1, -1, -1, -1}, // 13, 169
{1, 292, -1, -1, -1, -1, -1, -1}, // 17, 289
};
int n, id[N], vis[N]; vector <int> pr;
void sieve () {
	for (int i = 2; i < N; ++i) {
		if (!vis[i]) {
			id[i] = pr.size(), pr.push_back(i);
			for (int j = i; j < N; j += i) {
				vis[j] = i;
			}
		}
	}
}
namespace GF {
	int m, p, d, pl[M];
	struct elem {
		int x;
		elem (int _x = 0) : x(_x) {}
		elem compress (const poly &r) {
			x = 0;
			for (int i = d - 1; ~i; --i) {
				x = x * p + r[i];
			}
			return *this;
		}
		poly expand (elem e) {
			poly r(d);
			for (int i = 0; i < d; ++i) {
				r[i] = e.x % p, e.x /= p;
			}
			return r;
		}
		elem operator + (const elem &o) {
			poly F = expand(*this), G = expand(o);
			for (int i = 0; i < d; ++i) {
				F[i] = (F[i] + G[i]) % p;
			}
			return compress(F);
		}
		elem operator * (const elem &o) {
			poly F = expand(*this), G = expand(o), H(d + d, 0);
			for (int i = 0; i < d; ++i) {
				for (int j = 0; j < d; ++j) {
					H[i + j] = (H[i + j] + F[i] * G[j]) % p;
				}
			}
			for (int i = (d - 1) << 1; i > d - 1; --i) {
				H[i] = -H[i] % p, H[i] += H[i] >> 31 & p;
				for (int j = 1; j <= d; ++j) {
					H[i - j] = (H[i - j] + H[i] * pl[d - j]) % p;
				}
			}
			return compress(H);
		}
	} ;
	void get_poly () {
		for (int i = 0, x = R[id[p]][d - 1]; i <= d; ++i) {
			pl[i] = x % p, x /= p;
		}
	}
} using namespace GF;
int main () {
	sieve();
	cin >> n, m = n, p = vis[n];
	for (int x = n; x != 1; x /= p, ++d) {
		if (x % p != 0) {
			n = 1;
			break;
		}
	}
	if (n == 1) {
		puts("-1");
	} else {
		puts("0");
		get_poly();
		for (int i = 0; i < m; ++i) {
			for (int j = 0; j < m; ++j) {
				printf("%d%c", ((elem)i + (elem)j).x, j < n - 1 ? ' ' : '\n');
			}
		}
		for (int i = 0; i < n; ++i) {
			for (int j = 0; j < n; ++j) {
				printf("%d%c", ((elem)i * (elem)j).x, j < n - 1 ? ' ' : '\n');
			}
		}
	}
	return 0;
}
/*
4  : x ^ 2 + x     + 1             (111)2       = 7
8  : x ^ 3 + x     + 1             (1011)2      = 11
9  : x ^ 2 + 1                     (101)3       = 10
25 : x ^ 2 + 2                     (102)5       = 27
27 : x ^ 3 + 2x    + 1             (1021)3      = 34
81 : x ^ 4 + x     + 2             (10012)3     = 86
121: x ^ 2 + 1                     (101)11      = 122
125: x ^ 3 + x     + 1             (1011)5      = 131
169: x ^ 2 + 2                     (102)13      = 171
128: x ^ 7 + x     + 1             (10000011)2  = 131
243: x ^ 5 + 2x    + 1             (1000021)3   = 250
256: x ^ 8 + x ^ 4 + x ^ 3 + x + 1 (100011011)2 = 283
343: x ^ 3 + 2                     (1002)7      = 345
*/
posted @ 2019-11-11 09:43  psimonw  阅读(266)  评论(0编辑  收藏  举报