P3923 大学数学题 题解
littlez_meow
·
·
题解
混沌邪恶抽代入门题。
题目指路。
阅读本题解前,你需要了解域的定义和其他抽代基础知识。
既然是抽代题那就一个一个结论推吧。
解的存在性
【约定 1】在不易混淆的情况下,将域 (\mathbb{F},+,\times) 记为 \mathbb{F},其加法单位元记为 0,乘法单位元记为 1。本文中的域均为有限域。
【定义 1】(域特征)对于有限域 \mathbb{F},若 \exists p\in N^*,p\times1=0,则称最小的 p 为 \mathbb{F} 的特征。
【结论 1】有限域的特征是质数。
证明:设该有限域为 \mathbb{F},其特征为 p。考虑反证法,设 p=r\times s,1<r,s<p。
根据 0=p\times1,带入得到 0=(r\times s)\times 1。
根据乘法结合律得到 r\times(s\times 1)=0。
又 r\neq0,故 s\times1=0,与 p 最小矛盾,原命题得证。
【定义 2】(子域与域扩张)若 F 是 P 的非空子集,(P,+,\times) 是域且 (F,+,\times) 是域,则称 (F,+,\times) 是 (P,+,\times) 的子域,(P,+,\times) 是 (F,+,\times) 的扩张,记为 (F,+,\times)\subseteq(P,+,\times)。
【定义 3】(扩域的次数)若域 F\subseteq K,K 可视为 F- 向量空间,其次数称为扩域的次数,记为 [K:F]。
【结论 2】若域 F\subseteq K 且 F 为 q 元有限域,则 K 为 q^m 元有限域,其中 m=[K:F]。
证明:因为 K 可视为 F 上 m 维向量空间,取 K 一组基向量,每个系数均有 q 种取值,共 m 个系数,乘法原理即得。
【约定 2】我们记 \mathbb{F}_p 为包含 p 个元素的域。显然当 p 为质数时该域存在(模 p 意义下整数域 \mathbb{Z}_p),且其无任何真子域。
【结论 3】(有限域元素个数)一个有限域 \mathbb{F} 有 p^n 个元素,其中 p 为其特征。
证明:显然 \mathbb{F}_p\subseteq\mathbb{F},由结论 2 即得。
读者可以自己搜索 \mathbb{F}_p\subseteq\mathbb{F} 的证明。
由此可以得到:
【结论 4】(有限域的存在性和唯一性)\forall p,n,其中 p 为质数,n 为正整数,有限域 \mathbb{F}_{p^n} 存在且唯一。
该定理的证明与本题无关,在此略去。
综上,我们得到当 n 有且仅有一个质因数时,本题有解。即我们应在 case 3 与 case 14 输出 -1。
构造
请注意,有限域 \mathbb{F}_{p^m} 并不是模 p^m 意义下的整环。当且仅当 m=1 时二者同构。
也就是说,如果 n 为质数,直接当称普通模意义下的加法乘法就行。
那么,是质数的幂怎么办?设此时 n=p^m
根据结论 4,任何两个元素数相同的有限域同构。我们只需要找到一个现有的有限域 (\mathbb{F}_{p^m},+,\times),然后构造一个双射 f:\mathbb{F}_{p^m}\to\{0,1,2,\cdots,p^m-1\} 即可。
那么有什么呢?
确实,但是你需要定义向量间的乘法。因为要保证逆元,这是最难的一步。
换一个思路,还有什么同构?
所有系数在 $\mathbb{Z}_p$ 上的次数不超过 $m-1$ 次的多项式!
这下有乘法了,但是乘出来次数会超过 $m-1$。考虑模一个 $m$ 次多项式取模。
我们要保证所有非 $0$ 多项式均存在乘法逆元,这要多项式取模的模数是不可约的多项式。
为什么?
我们可以把多项式视为 $m$ 位的 $p$ 进制数。
若其有乘法逆元,则模数必须是质数,转换成多项式即不可约多项式。
最后的问题就是求不可约多项式了。
首先,如果多项式不首一,我们可以每个系数乘以首项系数逆元,不影响其是否可约。因此只用研究首一多项式。
其次,在求解的时候类似于质数枚举每个 $\lceil\dfrac m 2\rceil$ 阶多项式取模看有没有余项。
最劣的时间复杂度是 $O(n\sqrt nm^2)$,$n$ 这么小显然是跑得很快的。就算枚举到 $m$ 阶的也是 $O(n^2m^2)$,仍然跑得过。
## 代码
这里给出多项式板子和输出,找不可约多项式的部分就请自己写吧。
```cpp
#include<bits/stdc++.h>
#define F(i,a,b) for(int i(a),i##i##end(b);i<=i##i##end;++i)
#define R(i,a,b) for(int i(a),i##i##end(b);i>=i##i##end;--i)
#define ll long long
#define MOD p
using namespace std;
const int MAXN=30;
int n,m,p;
inline ll qpow(ll base,int expo){
ll res(1);
while(expo){
(expo&1)&&(res=res*base%MOD);
base=base*base%MOD,expo>>=1;
}
return res;
}
inline void meow(int&t){
t<0&&(t+=MOD);
t>=MOD&&(t-=MOD);
return;
}
struct poly{
int num[MAXN]={};
int len=0;
inline void init(){
while(!num[len]&&len>0) --len;
return;
}
inline void turn(int t){
while(t) num[len++]=t%MOD,t/=MOD;
init();
return;
}
inline poly operator+(const poly&a)const{
poly res;
res.len=max(a.len,len);
F(i,0,res.len) res.num[i]=num[i]+a.num[i],meow(res.num[i]);
res.init();
return res;
}
inline poly operator+(const int a)const{
poly res=*this;
int&qwq(res.num[0]);
qwq+=a;
meow(qwq);
return res;
}
inline poly operator-(const poly&a)const{
return a*(-1)+*this;
}
inline poly operator-(const int a)const{
return *this+(-a);
}
inline poly operator*(const poly&a)const{
poly x;
F(i,0,len) F(j,0,a.len){
int&qwq(x.num[i+j]);
qwq+=a.num[j]*1ll*num[i]%MOD;
qwq>=MOD&&(qwq-=MOD);
}
x.len=len+a.len;
x.init();
return x;
}
inline poly operator*(const int a)const{
poly res=*this;
F(i,0,len){
int&qwq(res.num[i]);
qwq=a*1ll*qwq%MOD;
meow(qwq);
}
return res;
}
inline bool operator<=(const poly&a)const{
if(len!=a.len) return len<=a.len;
R(i,len,0) if(num[i]!=a.num[i]) return num[i]<=a.num[i];
return 1;
}
inline poly operator<<(const int a)const{
poly res;
res.len=a+len;
F(i,0,len) res.num[a+i]=num[i];
return res;
}
inline poly operator%(const poly&a)const{
poly t=*this;
while(a<=t){
poly tmp=a*qpow(a.num[a.len],MOD-2)*t.num[t.len];
t=t-(tmp<<(t.len-a.len));
}
t.init();
return t;
}
inline bool check()const{//检查是否不可约
poly x=*this,y;
F(i,2,n-1){
poly t;
t.turn(i);
y=x%t;
if(y.len==0&&y.num[0]==0) return 0;
}
return 1;
}
inline void output(){
F(i,0,m) cout<<num[i]<<" ";
cout<<"\n";
return;
}
inline int decode(){
int res(0);
R(i,len,0) res=res*p+num[i];
return res;
}
}mod;
inline void findmod(){
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n;
switch(n){
case 2:case 3:case 19:case 89:case 181:case 233:{
cout<<"0\n";
F(i,0,n-1){
F(j,0,n-1){
cout<<(i+j)%n;
j!=n-1&&(cout<<" ");
}
cout<<"\n";
}
F(i,0,n-1){
F(j,0,n-1){
cout<<i*j%n;
j!=n-1&&(cout<<" ");
}
cout<<"\n";
}
return 0;
break;
}
case 6:case 143:{
cout<<"-1";
return 0;
break;
}
case 4:{
m=2,p=2;
break;
}
case 8:{
m=3,p=2;
break;
}
case 9:{
m=2,p=3;
break;
}
case 25:{
m=2,p=5;
break;
}
case 121:{
m=2,p=11;
break;
}
case 169:{
m=2,p=13;
break;
}
case 27:{
m=3,p=3;
break;
}
case 128:{
m=7,p=2;
break;
}
case 81:{
m=4,p=3;
break;
}
case 125:{
m=3,p=5;
break;
}
case 243:{
m=5,p=3;
break;
}
case 256:{
m=8,p=2;
break;
}
case 343:{
m=3,p=7;
break;
}
}
findmod();
cout<<"0\n";
F(i,0,n-1){
F(j,0,n-1){
poly ii,jj;
ii.turn(i),jj.turn(j);
cout<<(ii+jj).decode();
j!=n-1&&(cout<<" ");
}
cout<<"\n";
}
F(i,0,n-1){
F(j,0,n-1){
poly ii,jj;
ii.turn(i),jj.turn(j);
cout<<(ii*jj%mod).decode();
j!=n-1&&(cout<<" ");
}
cout<<"\n";
}
return 0;
}
```
完结撒花 qwq~