#include"big_uint.hpp"#include<stdexcept>template<typenameT>constexprboolbit_at(Ta,unsignedn){static_assert(std::is_arithmetic_v<T>);returna&(static_cast<T>(1)<<n);}// position of the highest non-zero bit.
// returns width of the argument type if a == 0.
template<typenameT>constexprunsignedhnz(Ta){static_assert(std::is_unsigned_v<T>);unsignedi=std::numeric_limits<T>::digits-1;for(;i!=std::numeric_limits<T>::max();--i)if(bit_at(a,i)){returni;}returni;}std::mt19937_64BigUInt::random_engine((std::random_device())());BigUInt::BigUInt(std::vector<uint32_t>vec):m_vec(vec){delete_trailing_zeros();}BigUInt&BigUInt::delete_trailing_zeros(){while(width()>1&&m_vec[width()-1]==0){m_vec.pop_back();}return*this;}BigUInt::BigUInt(){}BigUInt::BigUInt(int32_ti):m_vec({static_cast<uint32_t>(i)}){}BigUInt::BigUInt(int64_ti):BigUInt(static_cast<uint64_t>(i)){}BigUInt::BigUInt(uint32_ti):m_vec({i}){}BigUInt::BigUInt(uint64_ti):m_vec({static_cast<uint32_t>(i),static_cast<uint32_t>(i>>32)}){delete_trailing_zeros();}BigUInt::BigUInt(conststd::string&str):m_vec({0}){BigUIntbase(1);BigUIntten(10);for(uint64_ti=str.length()-1;i!=UINT64_MAX;--i){*this+=std::stoul(str.substr(i,1))*base;base*=ten;}delete_trailing_zeros();}uint64_tBigUInt::width()const{returnm_vec.size();}constuint32_t&BigUInt::operator[](uint64_ti)const{returnm_vec[i];}uint32_t&BigUInt::operator[](uint64_ti){returnm_vec[i];}BigUIntBigUInt::of_vector(std::vector<uint32_t>vec){returnBigUInt(vec);}BigUIntBigUInt::random(unsignedn){std::vector<uint32_t>vec(n);for(auto&i:vec){i=static_cast<uint32_t>(random_engine());}returnBigUInt(vec);}boolBigUInt::is_zero()const{for(uint32_ti=0;i<width();++i){if((*this)[i]!=0){returnfalse;}}returntrue;}BigUIntBigUInt::cshift_left(uint64_tshamt)const{BigUInttemp(*this);returntemp.shift_left(shamt);}BigUInt&BigUInt::shift_left(uint64_tshamt){if(shamt==0){return*this;}constuint64_tshamt_quot=shamt/32;constuint64_tshamt_rem=shamt%32;m_vec.resize(width()+shamt_quot+1);uint64_ti=width()-1;if(shamt_rem==0){// avoid undefined behavior by shifting 0 or 32.
for(;i!=shamt_quot-1;--i){(*this)[i]=(*this)[i-shamt_quot];}}else{constuint64_tshamt_rem_inv=32-shamt_rem;for(;i!=shamt_quot;--i){autolower=(*this)[i-shamt_quot-1]>>shamt_rem_inv;autoupper=(*this)[i-shamt_quot]<<shamt_rem;(*this)[i]=lower+upper;}(*this)[i--]=(*this)[0]<<shamt_rem;}for(;i!=UINT64_MAX;--i){(*this)[i]=0;}returndelete_trailing_zeros();}BigUIntBigUInt::cshift_right(uint64_tshamt)const{BigUInttemp(*this);returntemp.shift_right(shamt);}BigUInt&BigUInt::shift_right(uint64_tshamt){if(shamt==0){return*this;}constuint64_tshamt_quot=shamt/32;constuint64_tshamt_rem=shamt%32;if(shamt_rem==0){// avoid undefined behavior by shifting 0 or 32.
for(uint64_ti=0;i<width()-shamt_quot;++i){(*this)[i]=(*this)[i+shamt_quot];}}else{constuint64_tshamt_rem_inv=32-shamt_rem;for(uint64_ti=0;i<width()-shamt_quot-1;++i){autolower=(*this)[i+shamt_quot]>>shamt_rem;autoupper=(*this)[i+shamt_quot+1]<<shamt_rem_inv;(*this)[i]=lower+upper;}(*this)[width()-shamt_quot-1]=(*this)[width()-1]>>shamt_rem;}m_vec.resize(width()-shamt_quot);returndelete_trailing_zeros();}BigUIntBigUInt::operator-(){throwstd::invalid_argument("unary - of BigUInt");}BigUInt&BigUInt::operator++(){*this+=1;return*this;}BigUIntBigUInt::operator++(int){autotemp(*this);*this+=1;returntemp;}BigUInt&BigUInt::operator--(){*this-=1;return*this;}BigUIntBigUInt::operator--(int){autotemp(*this);*this-=1;returntemp;}booloperator==(constBigUInt&lhs,constBigUInt&rhs){returnlhs.m_vec==rhs.m_vec;}booloperator!=(constBigUInt&lhs,constBigUInt&rhs){returnlhs.m_vec!=rhs.m_vec;}booloperator<(constBigUInt&lhs,constBigUInt&rhs){if(lhs.width()<rhs.width()){returntrue;}if(lhs.width()>rhs.width()){returnfalse;}for(uint64_ti=lhs.width()-1;i!=UINT64_MAX;--i){if(lhs[i]==rhs[i]){continue;}returnlhs[i]<rhs[i];}returnfalse;}booloperator<=(constBigUInt&lhs,constBigUInt&rhs){returnlhs==rhs||lhs<rhs;}booloperator>(constBigUInt&lhs,constBigUInt&rhs){returnrhs<lhs;}booloperator>=(constBigUInt&lhs,constBigUInt&rhs){returnrhs<=lhs;}BigUInt&operator+=(BigUInt&lhs,constBigUInt&rhs){uint32_tcarry=0;uint32_ti;lhs.m_vec.resize(std::max(lhs.width(),rhs.width()));for(i=0;i<rhs.width();++i){lhs[i]+=carry;carry=lhs[i]<carry;lhs[i]+=rhs[i];carry|=lhs[i]<rhs[i];}for(;carry&&i<lhs.width();++i){++lhs[i];carry=lhs[i]<carry;}if(carry){lhs.m_vec.push_back(1);}returnlhs;}BigUIntoperator+(constBigUInt&lhs,constBigUInt&rhs){BigUIntans(lhs);returnans+=rhs;}// if lhs < rhs, result is undefined.
BigUInt&operator-=(BigUInt&lhs,constBigUInt&rhs){uint32_ti;uint32_tcarry=0;for(i=0;i<rhs.width();i++){lhs[i]-=carry;carry=lhs[i]==UINT32_MAX&&carry==1;carry|=lhs[i]<rhs[i];lhs[i]-=rhs[i];}for(;carry&&i<lhs.width();++i){--lhs[i];carry=lhs[i]==UINT32_MAX&&carry==1;}returnlhs.delete_trailing_zeros();}BigUIntoperator-(constBigUInt&lhs,constBigUInt&rhs){BigUIntans(lhs);returnans-=rhs;}BigUIntoperator*(constBigUInt&lhs,constBigUInt&rhs){BigUIntans;std::vector<uint32_t>lower(lhs.width());std::vector<uint32_t>upper(lhs.width()+1);for(uint32_ti=0;i<rhs.width();++i){for(uint32_tj=0;j<lhs.width();++j){upper[0]=0;lower[j]=lhs[j]*rhs[i];upper[j+1]=(static_cast<uint64_t>(lhs[j])*rhs[i])>>32;}ans+=(BigUInt(lower)+BigUInt(upper)).shift_left(32*i);}returnans;}BigUInt&operator*=(BigUInt&lhs,constBigUInt&rhs){lhs=lhs*rhs;returnlhs;}// knuth's division algorithm D.
// returns quotient, modifing dividend to be remainder.
staticBigUIntdivmod(BigUInt÷nd,constBigUInt&divisor){if(divisor.is_zero()){throwstd::invalid_argument("BigUInt : division by zero.");}if(dividend<divisor){return0;}// normalize dividend and divisor.
constuint64_tshamt=31-hnz(divisor[divisor.width()-1]);dividend.shift_left(shamt);const_cast<BigUInt&>(divisor).shift_left(shamt);uint64_tdiv_msb=divisor[divisor.width()-1];uint64_tdiv_ssb=divisor.width()==1?0:divisor[divisor.width()-2];std::vector<uint32_t>ans;ans.resize(dividend.width()-divisor.width()+1);for(uint64_ti=ans.size()-1;i!=UINT64_MAX;--i){uint64_tupper=(i+divisor.width()<dividend.width())?dividend[i+divisor.width()]:0;uint64_tlower=dividend[i+divisor.width()-1];uint64_tnum=(upper<<32)+lower;uint64_tq=num/div_msb;uint64_tr=num%div_msb;uint64_tidx=i+divisor.width()-2;while(r<UINT32_MAX&&(q>=UINT32_MAX||q*div_ssb>(r<<32)+(idx<dividend.width()?dividend[idx]:0))){q--;r+=div_msb;}BigUIntsub=(q*divisor).cshift_left(i*32);if(dividend<sub){q--;sub-=divisor.cshift_left(i*32);}ans[i]=static_cast<uint32_t>(q);dividend-=sub;}const_cast<BigUInt&>(divisor).shift_right(shamt);dividend.shift_right(shamt);returnBigUInt::of_vector(ans);}BigUIntoperator/(constBigUInt&lhs,constBigUInt&rhs){autotemp(lhs);returndivmod(temp,rhs);}BigUInt&operator/=(BigUInt&lhs,constBigUInt&rhs){returnlhs=lhs/rhs;}BigUIntoperator%(constBigUInt&lhs,constBigUInt&rhs){BigUInttemp(lhs);returntemp%=rhs;}BigUInt&operator%=(BigUInt&lhs,constBigUInt&rhs){divmod(lhs,rhs);returnlhs;}BigUIntBigUInt::pow(BigUIntexp)const{BigUIntx=1;for(;exp!=0;--exp){x*=*this;}returnx;}std::ostream&operator<<(std::ostream&lhs,constBigUInt&rhs){BigUIntbase(10);constBigUIntten(10);while(rhs>=base){base*=ten;}autotemp(rhs);while(base!=1){temp%=base;lhs<<(temp/(base/=ten))[0];}returnlhs;}
#include<array>#include<cassert>#include<ostream>// x * x > p である x を返す
// あまり賢くない
constexprintisqrt(intp){inti=2;for(;i*i<p;++i){}returni;}// p は素数か?
constexprboolis_prime(intp){for(inti=2;i<isqrt(i);++i){if(p%i==0){returnfalse;}}returntrue;}// i mod a を返す
constexprintmod_pos(inti,inta){intrem=i%a;// i < 0 だと rem < 0
if(rem>=0){returnrem;}else{returnrem+a;}}// 拡張ユークリッド法でax + by = gcd(p, a) を満たす(x, y)を求める
constexprstd::pair<int,int>ext_euclid(inta,intb){intr1=a;intr2=b;intx1=1;intx2=0;inty1=0;inty2=1;while(r2!=0){intr3=r1%r2;intq=r1/r2;intx3=x1-q*x2;inty3=y1-q*y2;r1=r2;r2=r3;x1=x2;x2=x3;y1=y2;y2=y3;}return{x1,y1};}// arr[i] * i = 1 (mod P) となる arr を返す
template<intP>constexprstd::array<int,P>construct_inverses(){std::array<int,P>arr={};for(inti=0;i<P;++i){arr[i]=ext_euclid(i,P).first;}returnarr;}// 位数Pの有限体を表す (Pは素数)
template<intP>classFiniteField{// Pが素数なことを確認
static_assert(P>1,"P in not prime");static_assert(is_prime(P),"P is not prime.");private:intm_val;// コンパイル時に計算される逆元の表
constexprstaticstd::array<int,P>inverses=construct_inverses<P>();public:FiniteField():m_val(0){}FiniteField(constint&val):m_val(mod_pos(val,P)){}// このexplicitを抜くと恐ろしい量のエラーが出る
explicitoperatorint()const{returnm_val;}FiniteField<P>inv()const{if(m_val==0){throwstd::runtime_error("division by zero");}returninverses[m_val];}// 以下は演算子のオーバーロード
FiniteField<P>operator-()const{returnFiniteField<P>(P-m_val);}FiniteField<P>&operator+=(constFiniteField<P>&other){m_val=mod_pos(m_val+other.m_val,P);return*this;}FiniteField<P>&operator-=(constFiniteField<P>&other){m_val=mod_pos(m_val-other.m_val,P);return*this;}FiniteField<P>&operator*=(constFiniteField<P>&other){m_val=mod_pos(m_val*other.m_val,P);return*this;}FiniteField<P>&operator/=(constFiniteField<P>&other){return*this*=other.inv();}// friendにして型の昇格を暗黙に行う
friendFiniteField<P>operator+(constFiniteField<P>&lhs,constFiniteField<P>&rhs){returnFiniteField<P>(lhs.m_val+rhs.m_val);}friendFiniteField<P>operator-(constFiniteField<P>&lhs,constFiniteField<P>&rhs){returnFiniteField<P>(lhs.m_val-rhs.m_val);}friendFiniteField<P>operator*(constFiniteField<P>&lhs,constFiniteField<P>&rhs){returnFiniteField<P>(lhs.m_val*rhs.m_val);}friendFiniteField<P>operator/(constFiniteField<P>&lhs,constFiniteField<P>&rhs){returnlhs*rhs.inv();}friendbooloperator==(constFiniteField<P>&lhs,constFiniteField<P>&rhs){returnrhs.m_val==lhs.m_val;}friendbooloperator!=(constFiniteField<P>&lhs,constFiniteField<P>&rhs){returnrhs.m_val!=lhs.m_val;}friendstd::ostream&operator<<(std::ostream&rhs,constFiniteField<P>&lhs){rhs<<lhs.m_val;returnrhs;}};