#include<iostream>#include<random>#include<vector>classFiniteField{intp,k;std::vector<int>mod;// Monic.// Remove leadings zeros of a polynomial.staticvoidtrim(std::vector<int>&poly){intm=poly.size();for(;m&&!poly[m-1];--m);poly.resize(m);}// Binary exponentiation mod p.intpow(inta,intb)const{intres=1,po=a;while(b){if(b&1)res=(longlong)res*po%p;po=(longlong)po*po%p;b>>=1;}returnres;}// Multiplicative inverse mod p.intinv(inta)const{returnpow(a,p-2);}// Polynomial GCD. Inputs are supposed to have no leading zeros.std::vector<int>poly_gcd(conststd::vector<int>&lhs,conststd::vector<int>&rhs)const{if(lhs.size()<rhs.size()){returnpoly_gcd(rhs,lhs);}elseif(rhs.size()){autorem=lhs;// remainder.longlongv=inv(rhs.back());for(inti=rem.size()-rhs.size();i>=0;--i){autod=v*(p-rem[i+rhs.size()-1])%p;for(intj=0;j<rhs.size();++j){rem[i+j]=(rem[i+j]+d*rhs[j])%p;}}trim(rem);// Remove leading zeros.returnpoly_gcd(rhs,rem);}else{returnlhs;}}// Polynomials Ex-GCD. Inputs are supposed to have no leading zeros.voidpoly_ex_gcd(conststd::vector<int>&lhs,conststd::vector<int>&rhs,std::vector<int>&x,std::vector<int>&y)const{if(lhs.size()<rhs.size()){poly_ex_gcd(rhs,lhs,y,x);}elseif(rhs.size()){std::vector<int>quo(lhs.size()-rhs.size()+1);// quotient.autorem=lhs;// remainder.longlongv=inv(rhs.back());for(inti=rem.size()-rhs.size();i>=0;--i){quo[i]=v*rem[i+rhs.size()-1]%p;longlongd=p-quo[i];// d = -quo[i].for(intj=0;j<rhs.size();++j){rem[i+j]=(rem[i+j]+d*rhs[j])%p;}}trim(rem);// Remove leading zeros.// Recursively ex_gcd.poly_ex_gcd(rhs,rem,y,x);// y -= a/b*x.if(y.size()<quo.size()+x.size()-1){y.resize(quo.size()+x.size()-1,0);}for(inti=0;i<quo.size();++i){for(intj=0;j<x.size();++j){y[i+j]=(y[i+j]-(longlong)quo[i]*x[j])%p;if(y[i+j]<0)y[i+j]+=p;}}trim(y);// Remove leading zeros.}else{// x = 1, y = 0.x.assign(1,inv(lhs.back()));y.clear();}}public:// Class for Finite Field Elements.structElement{constFiniteField*gf;std::vector<int>a;// Element initialization as zero.Element(constFiniteField*gf):gf(gf),a(gf->k){}// Element initialization from the numeric representation.Element(constFiniteField*gf,intid):gf(gf),a(gf->k){for(inti=0;i<gf->k;++i){a[i]=id%gf->p;id/=gf->p;}}// Generate the numeric representation from an element.intidx()const{intid=0;for(inti=gf->k-1;i>=0;--i){id=id*gf->p+a[i];}returnid;}// Access the i-th coefficient.int&operator[](inti){returna[i];}// Addition.Element&operator+=(constElement&rhs){for(inti=0;i<gf->k;++i){a[i]+=rhs.a[i];if(a[i]>=gf->p)a[i]-=gf->p;}return*this;}// Addition.Elementoperator+(constElement&rhs)const{Elementres(*this);res+=rhs;returnres;}// Subtraction.Element&operator-=(constElement&rhs){for(inti=0;i<gf->k;++i){a[i]-=rhs.a[i];if(a[i]<0)a[i]+=gf->p;}return*this;}// Subtraction.Elementoperator-(constElement&rhs)const{Elementres(*this);res-=rhs;returnres;}// Multiplication by a scalar.Element&operator*=(intx){for(inti=0;i<gf->k;++i){a[i]=(longlong)a[i]*x%gf->p;}return*this;}// Multiplication by a scalar.Elementoperator*(intx)const{Elementres(*this);res*=x;returnres;}// Multiplication by x.Element&shift(){longlongd=gf->p-a.back();// d = -a[k-1].for(inti=gf->k-1;i>=0;--i){a[i]=((i?a[i-1]:0)+d*gf->mod[i])%gf->p;}return*this;}// Multiplication.Element&operator*=(constElement&rhs){Elementprod(*this);*this*=rhs.a[0];for(intj=1;j<gf->k;++j){prod.shift();*this+=prod*rhs.a[j];}return*this;}// Multiplication.Elementoperator*(constElement&rhs)const{Elementres(*this);res*=rhs;returnres;}// Binary exponentiation.Elementpow(intb)const{Elementres(gf,1);Elementpo(*this);while(b){if(b&1)res*=po;po=po*po;b>>=1;}returnres;}// Multiplicative inverse.Elementinv()const{Elementres(gf);auto&x=res.a;std::vector<int>y;autolhs=a;trim(lhs);autorhs=gf->mod;gf->poly_ex_gcd(lhs,rhs,x,y);x.resize(gf->k);returnres;}// Division.Element&operator/=(constElement&rhs){*this*=rhs.inv();return*this;}// Division.Elementoperator/(constElement&rhs)const{Elementres(*this);res/=rhs;returnres;}};private:// Check whether the current MOD is irreducible.boolcheckIrreducible()const{Elementf(this,p);for(intj=1;j<k;++j){// F = X^{p^j} mod MOD.f=f.pow(p);// G = X^{p^j}-X mod MOD.autog=f.a;g[1]=g[1]?g[1]-1:p-1;trim(g);// H = MOD.autoh=mod;// Reducible if deg(GCD(G,H))>0.if(poly_gcd(h,g).size()>1)returnfalse;}returntrue;}public:FiniteField(intp,intk):p(p),k(k),mod(k+1,1){do{// Randomly generate a polynomial.for(inti=0;i<k;++i){mod[i]=rand()%p;}}while(!checkIrreducible());}};intmain(){intp=13331,k=50;FiniteFieldgf(p,k);FiniteField::Elemente1(&gf,rand()+1);FiniteField::Elemente2(&gf,rand()+1);FiniteField::Elemente3(&gf,rand()+1);// Test Frobenius endomorphism.std::cout<<((e1*e2+e3).pow(p)-e1.pow(p)*e2.pow(p)-e3.pow(p)).idx();// Test inverse.std::cout<<((e1*e2).inv()-e1.inv()/e2).idx();return0;}