1 条题解

  • 0
    @ 2025-8-24 21:54:07

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar Drystynt
    Cokernel

    搬运于2025-08-24 21:54:07,当前版本为作者最后更新于2021-01-04 11:41:38,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    Updated On 2021/9/19. 笔者学了抽象代数之后,做了一些补充,同时修改了一些对专业术语的措辞。增加的地方加了P.S.。P.S.的部分比较难懂,若无法理解可以不看它们。不看P.S.的部分对全文理解不会有过多的影响。


    一个有趣的抽象代数题。

    开始我也是没有思路,于是就开始碰碰运气。我们先试一下-1:

    case 6:case 143:cout<<"-1";break;
    

    发现自己得了10分。对的是哪两个点呢?

    第3和第14个,此时 n=6n=6143143 。注意到其他的数都是素数的不小于1的整数幂,而这两个不是,于是猜想:不存在大于1个素因子的合数之元的有限域。

    于是我们不管这些合数了,只看素数的不小于1的整数幂。先观察素数:因为素数的完全剩余系与简化剩余系是相同的,我们直接把两个数相加并模这个素数即可。[P.S. 这里在有限域中即为:GF(p)=Z/pZ.GF(p)=\mathbb{Z}/p\mathbb{Z}.]

    case 3:case 19:case 89:case 181:case 233:
    {
       cout<<"0"<<endl;
       for(int i=0;i<n;i++)
       {
         for(int j=0;j<n;j++)
         {
            cout<<(i+j)%n;
            if(j==n-1)continue;
            else cout<<' ';
         }
         cout<<endl;
       }
       for(int i=0;i<n;i++)
       {
         for(int j=0;j<n;j++)
         {
            cout<<(i*j)%n;
            if(j==n-1)continue;
            else cout<<' ';
         }
         cout<<endl;
       }
    }break;
    

    于是就3535分到手了

    后面怎么办呢?

    我试了一个小时n=4n=4的情况,终于试出来:

    if(n==4)
    {
    	cout<<0<<endl;
    	cout<<"0 1 2 3\n1 0 3 2\n2 3 0 1\n3 2 1 0\n0 0 0 0\n0 1 2 3\n0 2 3 1\n0 3 1 2"<<endl;
    	return 0;
    }
    

    然后没有思绪。

    于是在网上找"有限域",发现需要:

    相加或相乘再模 pp ,就是 pp 进制中个位的运算。那么 n=pkn=p^k 的情况也就能解决了。

    这里,每个有限域中的数都是一个多项式的值的 pp 进制的一个数位。于是解决了加法。

    找出一个系数在 [0,p)[0,p) 中的 kk 次既约多项式,这里 k8k\leqslant 8 .关键是想要如何找到。

    再把它与原多项式相乘再模 pp 处理即可,正确性显然。

    p=2p=2 时,加法只需要把两个数异或一下。乘法怎么办?

    3×53\times 5 的例子:

    3=(11)2=p+1(p=2)3=(11)_2=p+1(p=2)

    5=(101)2=p2+1(p=2)5=(101)_2=p^2+1(p=2)

    3×5=(p+1)(p2+1)=p3+p2+p+13\times 5=(p+1)(p^2+1)=p^3+p^2+p+1

    但这个数已经大于 88 了,于是我们模一个不可约多项式 p3+p+1p^3+p+1,得到 p2p^2,于是 3×5=43\times 5=4.

    当然多项式也不好找,需要自己动脑筋。

    下附所有22的幂情况标程:

    #include<bits/stdc++.h>
    using namespace std;
    #define N 17
    int p;
    struct f//多项式
    {
    	int a[N];
    	int dr()
    	{
    		for(int i=N-1;i>=0;i--)
    			if(a[i]!=0)	return i;
    		return 0;	
    	}
    	inline void clr()
    	{
    		for(int i=0;i<N;i++)	a[i]=0;
    		return;
    	}
    	inline void mod()
    	{
    		for(int i=0;i<N;i++)	a[i]%=p;
    		return;
    	}
    };
    inline f mul(f x,int l)//数乘
    {
    	for(int i=0;i<N;i++)	x.a[i]*=l;
    	return x;
    }
    f gt(int x)//数转换为多项式
    {
    	f ans;ans.clr();
    	for(int i=0;;i++)
    	{
    		if(x==0)	return ans;
    		else{ans.a[i]=x%p;x/=p;}
    	}
    }
    int ungt(f ans)//多项式转为数
    {
    	int x=0;
    	for(int i=ans.dr();i>=0;i--)
    		x=(x*p)+ans.a[i];
    	return x; 
    }
    f add(f x,f y)//加
    {
    	for(int i=0;i<=N;i++)
    		x.a[i]=(x.a[i]+y.a[i])%p;
    	return x;
    }
    f yiw(f x,int sum)//移位
    {
    	for(int i=x.dr();i>=0;i--)	x.a[i+sum]=x.a[i];
    	for(int i=sum-1;i>=0;i--)	x.a[i]=0;
    	return x;
    }
    f prod(f x,f y)//多项式相乘
    {
    	f ans;ans.clr();
    	for(int i=0;i<=x.dr();i++)
    	{
    		if(x.a[i]!=0)	ans=add(ans,mul(yiw(y,i),x.a[i]));
    	}
    	ans.mod();
    	return ans;
    }
    f Mod(f x,f y)//多项式取模
    {
    	int sg=y.dr()-1;
    	for(int i=x.dr();i>=sg+1;i--)
    	{
    		if(x.a[i]==0)	continue;
    		else
    		{
    			x=add(x,mul(yiw(y,i-sg-1),p-x.a[i]));
    			x.mod();
    		}
    	}
    	return x;
    }
    f Num(int x)//找多项式
    {
    	f ans;ans.clr();
    	if (x==8)ans.a[0]=ans.a[1]=ans.a[3]=1;
    	if (x==256)	ans.a[8]=ans.a[4]=ans.a[3]=ans.a[1]=ans.a[0]=1;
    	if (x==16)	ans.a[2]=ans.a[4]=ans.a[3]=ans.a[1]=ans.a[0]=1;
    	if (x==128)	ans.a[7]=ans.a[6]=ans.a[5]=ans.a[2]=ans.a[0]=1;
    	return ans;
    }
    

    主函数内的:

    	case 256:case 128:case 8:
            {
            	p=2;
                cout<<0<<endl;
                for(int i=0;i<n;i++)
                {
                    for(int j=0;j<n;j++)
                    {
                        cout<<(i^j);
                        if(j==n-1)continue;
                        else cout<<' ';
                    }
                    cout<<endl;
                }
                for(int i=0;i<n;i++)
                {
                	for(int j=0;j<n;j++)
                    {
                        f x=gt(i);
                        f y=gt(j);
                        f z=prod(x,y);
                        z=Mod(z,Num(n));
                        int ans=ungt(z);
                        cout<<ans;
                        if(j==n-1)continue;
                        else cout<<' ';
                    }
                    cout<<endl;
    			}
            }break;
    

    最后,给出满分程序,但是多项式请自己找。

    #include<bits/stdc++.h>
    using namespace std;
    #define N 17
    int p;
    struct f
    {
    	int a[N];
    	int dr()
    	{
    		for(int i=N-1;i>=0;i--)
    			if(a[i]!=0)	return i;
    		return 0;	
    	}
    	inline void clr()
    	{
    		for(int i=0;i<N;i++)	a[i]=0;
    		return;
    	}
    	inline void mod()
    	{
    		for(int i=0;i<N;i++)	a[i]%=p;
    		return;
    	}
    };
    inline f mul(f x,int l)
    {
    	for(int i=0;i<N;i++)	x.a[i]*=l;
    	return x;
    }
    f gt(int x)
    {
    	f ans;ans.clr();
    	for(int i=0;;i++)
    	{
    		if(x==0)	return ans;
    		else{ans.a[i]=x%p;x/=p;}
    	}
    }
    int ungt(f ans)
    {
    	int x=0;
    	for(int i=ans.dr();i>=0;i--)
    		x=(x*p)+ans.a[i];
    	return x; 
    }
    f add(f x,f y)
    {
    	for(int i=0;i<=N;i++)
    		x.a[i]=(x.a[i]+y.a[i])%p;
    	return x;
    }
    f yiw(f x,int sum)
    {
    	for(int i=x.dr();i>=0;i--)	x.a[i+sum]=x.a[i];
    	for(int i=sum-1;i>=0;i--)	x.a[i]=0;
    	return x;
    }
    f prod(f x,f y)
    {
    	f ans;ans.clr();
    	for(int i=0;i<=x.dr();i++)
    	{
    		if(x.a[i]!=0)	ans=add(ans,mul(yiw(y,i),x.a[i]));
    	}
    	ans.mod();
    	return ans;
    }
    f Mod(f x,f y)
    {
    	int sg=y.dr()-1;
    	for(int i=x.dr();i>=sg+1;i--)
    	{
    		if(x.a[i]==0)	continue;
    		else
    		{
    			x=add(x,mul(yiw(y,i-sg-1),p-x.a[i]));
    			x.mod();
    		}
    	}
    	return x;
    }
    f Num(int x)
    {
    	//自己找
    }
    int main()
    {
        ios::sync_with_stdio(0);
        int n;
        cin>>n;
        if(n==4){cout<<0<<endl;cout<<"0 1 2 3\n1 0 3 2\n2 3 0 1\n3 2 1 0\n0 0 0 0\n0 1 2 3\n0 2 3 1\n0 3 1 2"<<endl;return 0;}
        switch(n)
        {
            case 6:case 143:cout<<"-1";break;
            case 3:case 19:case 89:case 181:case 233:
            {
                cout<<"0"<<endl;
                for(int i=0;i<n;i++)
                {
                    for(int j=0;j<n;j++)
                    {
                        cout<<(i+j)%n;
                        if(j==n-1)continue;
                        else cout<<' ';
                    }
                    cout<<endl;
                }
                for(int i=0;i<n;i++)
                {
                    for(int j=0;j<n;j++)
                    {
                        cout<<(i*j)%n;
                        if(j==n-1)continue;
                        else cout<<' ';
                    }
                    cout<<endl;
                }
            }break;
            case 256:case 128:case 8:
            {
            	p=2;
                cout<<0<<endl;
                for(int i=0;i<n;i++)
                {
                    for(int j=0;j<n;j++)
                    {
                        cout<<(i^j);
                        if(j==n-1)continue;
                        else cout<<' ';
                    }
                    cout<<endl;
                }
                for(int i=0;i<n;i++)
                {
                	for(int j=0;j<n;j++)
                    {
                        f x=gt(i);
                        f y=gt(j);
                        f z=prod(x,y);
                        z=Mod(z,Num(n));
                        int ans=ungt(z);
                        cout<<ans;
                        if(j==n-1)continue;
                        else cout<<' ';
                    }
                    cout<<endl;
    			}
            }break;
            default:
            {
            	p=...//自己写if
            	cout<<0<<endl;
            	for(int i=0;i<n;i++)
                {
                    for(int j=0;j<n;j++)
                    {
                        f x=gt(i);
                        f y=gt(j);
                        f z=add(x,y);
                        int ans=ungt(z);
                        cout<<ans;
                        if(j==n-1)continue;
                        else cout<<' ';
                    }
                    cout<<endl;
                }
                for(int i=0;i<n;i++)
                {
                	for(int j=0;j<n;j++)
                    {
                        f x=gt(i);
                        f y=gt(j);
                        f z=prod(x,y);
                        z=Mod(z,Num(n));
                        int ans=ungt(z);
                        cout<<ans;
                        if(j==n-1)continue;
                        else cout<<' ';
                    }
                    cout<<endl;
    			}
    		}
        }
        return 0;
    }
    

    P.S.

    这里简略地证明一下有限域的元素个数必为 pnp^n 的形式,其中 pp 为素数,下文中字母 pp 未加说明均为素数。我们假定读者学过群论。

    "环"的定义详见

    环同态基本定理与群同态基本定理很类似。学过群论的应该都知道群同态基本定理,所以笔者认为不必介绍环的像、kernel\text{kernel}(核)、环同态和环同态基本定理。

    设有限域为 GF(k),kGF(k),k 为有限域元素个数。显然存在 GF(p)GF(p).

    定义1.设 FF 是域。使得 n1=0n·1=0 的最小正整数 nn 称为 FF特征。若不存在这样的正整数称其特征为 00。我们把特征记为 char(F)char(F).

    引理1. 设 FF 为一个域,若 char(F)>0char(F)>0 ,则 char(F)char(F) 必为素数。

    证明:反证法,设 n=char(F)n=char(F),若 nn 为合数,则 n=uvn=uvu>1,v>1u>1,v>1 为整数。故 (u1)(v1)=(uv)1=n1=0(u·1)(v·1)=(uv)·1=n·1=0. 由 nn 的最小性知 u10u·1≠0 ,从而 u1u·1 有逆元 (u1)1(u·1)^{-1}。上式两端同乘 (u1)1(u·1)^{-1}v1=0v·1=0,与 nn 的最小性矛盾!

    引理2.FF 为域。若 char(F)=p>0char(F)=p>0,则 FF 必有与 GF(p)GF(p) 同构的子域。

    证明:定义映射

    φ:ZF\varphi: \mathbb{Z} \rightarrow F nn1n \mapsto n·1

    显然 φ\varphi 是环同态。我们断言 kerφ=pZ.\ker \varphi=p\mathbb{Z}.nkerφ,n∈\ker \varphi,n1=0F.n·1=0∈F.n=qp+r (q,rZ,0r<q)n=qp+r\ (q,r∈\mathbb{Z}, 0\leqslant r<q) 则有 0=n1=q(p1)+r1=r10=n·1=q(p·1)+r·1=r·1,由 charchar 的定义知 pp 只能为 00. 故 npZn∈p\mathbb{Z},这说明 kerφpZ.\ker \varphi \subseteq p\mathbb{Z}.

    反之,对 npZn∈p\mathbb{Z}n=pqn=pq ,则 φ(n)=(qp)1=q(p1)=0\varphi(n)=(qp)·1=q(p·1)=0,从而 nkerφn∈\ker \varphi,即 pZkerφ.p\mathbb{Z}\subseteq\ker \varphi.

    故断言成立。由环同态基本定理, $GF(p)=\mathbb{Z}/p\mathbb{Z}\cong \text{im}\ \varphi $.

    im φ\text{im}\ \varphi FF 的子域,故证毕。

    回到原问题,设 KK 为有限域,则 KK 包含 GF(p)GF(p) ,且 K/GF(p)K/GF(p) 必为有限扩张(定义见),故 K|K| 只有一个素因子,证毕!

    P.S.P.S. 题外话:可以证明所有的 GF(pn)GF(p^n) 均同构,所以上面的构造相当于是唯一的。

    • 1

    信息

    ID
    2882
    时间
    1000~3000ms
    内存
    125MiB
    难度
    7
    标签
    递交数
    0
    已通过
    0
    上传者