#pragma once
#include"nimber.hpp"
#include"sweep-restore.hpp"template<typenameN>structNimberToField{usinguint=decltype(N::x);staticconstexprintS=sizeof(uint)*8;vector<uint>ftn,ntf;NimberToField(Nproot){ftn.resize(S);Ncur=1;for(inti=0;i<S;i++){ftn[i]=cur.x;cur*=proot;}Sweepsweep{ftn};ntf.resize(S);for(inti=0;i<S;i++){autoans=sweep.restore(1<<i);uintbit{};for(auto&x:ans.second)bit^=uint{1}<<x;ntf[i]=bit;}}uintnimber2field(Nn){uintres=0,x=n.x;for(;x;x&=x-1)res^=ntf[__builtin_ctzll(x)];returnres;}Nfield2nimber(uintx){uintres=0;for(;x;x&=x-1)res^=ftn[__builtin_ctzll(x)];returnres;}};/**
* @brief Nimber <-> 多項式環
*/
#line 2 "math/nimber-to-field.hpp"
#line 2 "math/nimber.hpp"
#line 2 "math/garner.hpp"
// input : a, M (0 < a < M)// output : pair(g, x) s.t. g = gcd(a, M), xa = g (mod M), 0 <= x < b/gtemplate<typenameuint>pair<uint,uint>gcd_inv(uinta,uintM){assert(M!=0&&0<a);a%=M;uintb=M,s=1,t=0;while(true){if(a==0)return{b,t+M};t-=b/a*s;b%=a;if(b==0)return{a,s};s-=a/b*t;a%=b;}}// 入力 : 0 <= rem[i] < mod[i], 1 <= mod[i]// 存在するとき : return {rem, mod}// 存在しないとき : return {0, 0}template<typenameT,typenameU>pair<unsignedlonglong,unsignedlonglong>garner(constvector<T>&rem,constvector<U>&mod){assert(rem.size()==mod.size());usingu64=unsignedlonglong;u64r0=0,m0=1;for(inti=0;i<(int)rem.size();i++){assert(1<=mod[i]);assert(0<=rem[i]&&rem[i]<mod[i]);u64m1=mod[i],r1=rem[i]%m1;if(m0<m1)swap(r0,r1),swap(m0,m1);if(m0%m1==0){if(r0%m1!=r1)return{0,0};continue;}u64g,im;tie(g,im)=gcd_inv(m0,m1);u64y=r0<r1?r1-r0:r0-r1;if(y%g!=0)return{0,0};u64u1=m1/g;y=y/g%u1;if(r0>r1&&y!=0)y=u1-y;u64x=y*im%u1;r0+=x*m0;m0*=u1;}return{r0,m0};}/**
* @brief Garner's algorithm
*/#line 4 "math/nimber.hpp"
namespaceNimberImpl{usingu16=uint16_t;usingu32=uint32_t;usingu64=uint64_t;structcalc8{u16dp[1<<8][1<<8];constexprcalc8():dp(){dp[0][0]=dp[0][1]=dp[1][0]=0;dp[1][1]=1;for(inte=1;e<=3;e++){intp=1<<e,q=p>>1;u16ep=1u<<p,eq=1u<<q;for(u16i=0;i<ep;i++){for(u16j=i;j<ep;j++){if(i<eq&&j<eq)continue;if(min(i,j)<=1u){dp[i][j]=dp[j][i]=i*j;continue;}u16iu=i>>q,il=i&(eq-1);u16ju=j>>q,jl=j&(eq-1);u16u=dp[iu][ju],l=dp[il][jl];u16ul=dp[iu^il][ju^jl];u16uq=dp[u][eq>>1];dp[i][j]=((ul^l)<<q)^uq^l;dp[j][i]=dp[i][j];}}}}}constexprc8;structcalc16{staticconstexpru16proot=10279;staticconstexpru32ppoly=92191;staticconstexprintorder=65535;u16base[16],exp[(1<<18)+100];intlog[1<<16];private:constexpru16d(u32x){return(x<<1)^(x<32768u?0:ppoly);}constexpru16naive(u16i,u16j){if(min(i,j)<=1u)returni*j;u16q=8,eq=1u<<8;u16iu=i>>q,il=i&(eq-1);u16ju=j>>q,jl=j&(eq-1);u16u=c8.dp[iu][ju];u16l=c8.dp[il][jl];u16ul=c8.dp[iu^il][ju^jl];u16uq=c8.dp[u][eq>>1];return((ul^l)<<q)^uq^l;}public:constexprcalc16():base(),exp(),log(){base[0]=1;for(inti=1;i<16;i++)base[i]=naive(base[i-1],proot);exp[0]=1;for(inti=1;i<order;i++)exp[i]=d(exp[i-1]);u16*pre=exp+order+1;pre[0]=0;for(intb=0;b<16;b++){intis=1<<b,ie=is<<1;for(inti=is;i<ie;i++)pre[i]=pre[i-is]^base[b];}for(inti=0;i<order;i++)exp[i]=pre[exp[i]],log[exp[i]]=i;intie=2*order+30;for(inti=order;i<ie;i++)exp[i]=exp[i-order];for(unsignedinti=ie;i<sizeof(exp)/sizeof(u16);i++)exp[i]=0;log[0]=ie+1;}constexpru16prod(u16i,u16j)const{returnexp[log[i]+log[j]];}// exp[3] = 2^{15} = 32768constexpru16Hprod(u16i,u16j)const{returnexp[log[i]+log[j]+3];}constexpru16H(u16i)const{returnexp[log[i]+3];}constexpru16H2(u16i)const{returnexp[log[i]+6];}}constexprc16;u16product16(u16i,u16j){returnc16.prod(i,j);}constexpru32product32(u32i,u32j){u16iu=i>>16,il=i&65535;u16ju=j>>16,jl=j&65535;u16l=c16.prod(il,jl);u16ul=c16.prod(iu^il,ju^jl);u16uq=c16.Hprod(iu,ju);return(u32(ul^l)<<16)^uq^l;}// (+ : xor, x : nim product, * : integer product)// i x j// = (iu x ju + il x ju + iu x ji) * 2^{16}// + (iu x ju x 2^{15}) + il x jl// (assign ju = 2^{15}, jl = 0)// = ((iu + il) x 2^{15}) * 2^{16} + (iu x 2^{15} x 2^{15})constexpru32H(u32i){u16iu=i>>16;u16il=i&65535;return(u32(c16.H(iu^il))<<16)^c16.H2(iu);}constexpru64product64(u64i,u64j){u32iu=i>>32,il=i&u32(-1);u32ju=j>>32,jl=j&u32(-1);u32l=product32(il,jl);u32ul=product32(iu^il,ju^jl);u32uq=H(product32(iu,ju));return(u64(ul^l)<<32)^uq^l;}}// namespace NimberImpltemplate<typenameuint,uint(*prod)(uint,uint)>structNimberBase{usingN=NimberBase;uintx;NimberBase():x(0){}NimberBase(uint_x):x(_x){}staticNid0(){return{};}staticNid1(){return{1};}N&operator+=(constN&p){x^=p.x;return*this;}N&operator-=(constN&p){x^=p.x;return*this;}N&operator*=(constN&p){x=prod(x,p.x);return*this;}Noperator+(constN&p)const{returnx^p.x;}Noperator-(constN&p)const{returnx^p.x;}Noperator*(constN&p)const{returnprod(x,p.x);}booloperator==(constN&p)const{returnx==p.x;}booloperator!=(constN&p)const{returnx!=p.x;}Npow(uint64_tn)const{Na=*this,r=1;for(;n;a*=a,n>>=1)if(n&1)r*=a;returnr;}friendostream&operator<<(ostream&os,constN&p){returnos<<p.x;}// calculate log_a (b)uintdiscrete_logarithm(Ny)const{assert(x!=0&&y!=0);vector<uint>rem,mod;for(uintp:{3,5,17,257,641,65537,6700417}){if(uint(-1)%p)continue;uintq=uint(-1)/p;uintSTEP=1;while(4*STEP*STEP<p)STEP*=2;// a^m = z を満たす 1 以上の整数 m を返すautoinside=[&](Na,Nz)->uint{unordered_map<uint,int>mp;Nbig=1,now=1;// x^mfor(inti=0;i<int(STEP);i++){mp[z.x]=i,z*=a,big*=a;}for(intstep=0;step<int(p+10);step+=STEP){now*=big;if(mp.find(now.x)!=mp.end())return(step+STEP)-mp[now.x];}returnuint(-1);};Nxq=(*this).pow(q),yq=y.pow(q);if(xq==1andyq==1)continue;if(xq==1andyq!=1)returnuint(-1);uintres=inside(xq,yq);if(res==uint(-1))returnuint(-1);rem.push_back(res%p);mod.push_back(p);}returngarner(rem,mod).first;}uintis_primitive_root()const{if(x==0)returnfalse;for(uintp:{3,5,17,257,641,65537,6700417}){if(uint(-1)%p!=0)continue;if((*this).pow(uint(-1)/p)==1)returnfalse;}returntrue;}};usingNimber16=NimberBase<uint16_t,NimberImpl::product16>;usingNimber32=NimberBase<uint32_t,NimberImpl::product32>;usingNimber64=NimberBase<uint64_t,NimberImpl::product64>;usingNimber=Nimber64;/**
* @brief Nim Product
* @docs docs/math/nimber.md
*/#line 2 "math/sweep-restore.hpp"
template<typenameT>structSweep{usingP=pair<T,unordered_set<int>>;vector<P>basis;Sweep(){}Sweep(constvector<T>&v){for(inti=0;i<(int)v.size();i++)add(v[i],i);}// x を id と共に追加voidadd(Tx,intid){Pv{x,{id}};for(P&b:basis){if(v.first>(v.first^b.first))apply(v,b);}if(v.first!=T{})basis.push_back(v);}// pair(x を復元できるか?, {復元した時の ID の集合})pair<bool,vector<int>>restore(Tx){Pv{x,{}};for(P&b:basis){if(v.first>(v.first^b.first))apply(v,b);}if(v.first!=T{})return{false,{}};vector<int>res;for(auto&n:v.second)res.push_back(n);sort(begin(res),end(res));return{true,res};}private:voidapply(P&p,constP&o){p.first^=o.first;for(auto&x:o.second)apply(p.second,x);}voidapply(unordered_set<int>&s,intx){if(s.count(x)){s.erase(x);}else{s.insert(x);}}};/**
* @brief 掃き出し法(復元付き)
*/#line 5 "math/nimber-to-field.hpp"
template<typenameN>structNimberToField{usinguint=decltype(N::x);staticconstexprintS=sizeof(uint)*8;vector<uint>ftn,ntf;NimberToField(Nproot){ftn.resize(S);Ncur=1;for(inti=0;i<S;i++){ftn[i]=cur.x;cur*=proot;}Sweepsweep{ftn};ntf.resize(S);for(inti=0;i<S;i++){autoans=sweep.restore(1<<i);uintbit{};for(auto&x:ans.second)bit^=uint{1}<<x;ntf[i]=bit;}}uintnimber2field(Nn){uintres=0,x=n.x;for(;x;x&=x-1)res^=ntf[__builtin_ctzll(x)];returnres;}Nfield2nimber(uintx){uintres=0;for(;x;x&=x-1)res^=ftn[__builtin_ctzll(x)];returnres;}};/**
* @brief Nimber <-> 多項式環
*/