板子
板子
高精
namespace BIG_num{
using cpx=complex<double>; const double PI=acos(-1); vector<cpx>roots= {{0,0},{1,0}};
void ensure_capacity(int min_capacity) {
for(int len=roots.size();len<min_capacity;len*=2) for(int i=len>>1; i<len; i++) {
roots.emplace_back(roots[i]); double angle=2*PI*(2*i+1-len)/(len*2);
roots.emplace_back(cos(angle),sin(angle));
}
}
void fft(vector<cpx>&z,bool inverse) {
int n=z.size(); ensure_capacity(n);
for(int i=1,j=0;i<n;i++){int BIGt=n>>1; for(; j>=BIGt; BIGt>>=1) j-=BIGt; j+=BIGt; if(i<j) swap(z[i],z[j]);}
for(int len=1;len<n;len<<=1) for(int i=0;i<n;i+=len*2) for(int j=0;j<len;j++){
cpx root=inverse?conj(roots[j+len]):roots[j+len],u=z[i+j],v=z[i+j+len]*root;
z[i+j]=u+v;z[i+j+len]=u-v;
}
if(inverse)for(int i=0; i<n; i++)z[i]/=n;
}
vector<int>multiply_BIG(const vector<int>&a,const vector<int>&b,int base) {
int need=a.size()+b.size(); int n=1; while(n<need) n<<=1; vector<cpx> p(n);
for(int i=0;i<n;i++) p[i]=cpx(i<(int)a.size()?a[i]:0,i<(int)b.size()?b[i]:0);
fft(p,false); vector<cpx>ab(n); cpx r(0,-0.25);
for(int i=0;i<n;i++){int j=(n-i)&(n-1); ab[i]=(p[i]*p[i]-conj(p[j]*p[j]))*r;}
fft(ab,true); vector<int>result(need); long long carry=0;
for(int i=0;i<need;i++){long long d=(long long)(ab[i].real()+0.5)+carry; carry=d/base;result[i]=d%base;}
return result;
}
vector<int>multiply_mod(const vector<int>&a,const vector<int>&b,int m) {
int need=a.size()+b.size()-1; int n=1; while(n<need)n<<=1; vector<cpx>A(n);
for(size_t i=0;i<a.size();i++){int x=(a[i]%m+m)%m; A[i]=cpx(x&((1<<15)-1),x>>15);}
fft(A,false); vector<cpx>B(n);
for(size_t i=0;i<b.size();i++){int x=(b[i]%m+m)%m; B[i]=cpx(x&((1<<15)-1),x>>15);}
fft(B,false); vector<cpx>fa(n); vector<cpx>fb(n);
for(int i=0,j=0;i<n;i++,j=n-i) {
cpx a1=(A[i]+conj(A[j]))*cpx(0.5,0),a2=(A[i]-conj(A[j]))*cpx(0,-0.5);
cpx b1=(B[i]+conj(B[j]))*cpx(0.5,0),b2=(B[i]-conj(B[j]))*cpx(0,-0.5);
fa[i]=a1*b1+a2*b2*cpx(0,1); fb[i]=a1*b2+a2*b1;
}
fft(fa,true); fft(fb,true); vector<int>res(need);
for(int i=0;i<need;i++){
long long aa=(long long)(fa[i].real()+0.5),bb=(long long)(fb[i].real()+0.5),cc=(long long)(fa[i].imag()+0.5);
res[i]=(aa%m+(bb%m<<15)+(cc%m<<30))%m;
}
return res;
}
constexpr int digits(int base)noexcept{return base<=1?0:1+digits(base/10);}
constexpr int base=1000000000,base_digits=digits(base),fft_base=10000,fft_base_digits=digits(fft_base);
struct Big {
vector<int>z; int sign;
Big(long long v=0){*this=v;}
Big &operator=(long long v){
sign=v<0?-1:1,v*=sign,z.clear();
for(;v>0;v=v/base) z.push_back((int)(v%base));
return *this;
}
Big (const string &s){read(s);}
Big &operator+=(const Big &other){
if(sign==other.sign) for(int i=0,carry=0;i<(int)other.z.size()||carry;++i){
if(i==(int)z.size()) z.push_back(0);
z[i]+=carry+(i<(int)other.z.size()?other.z[i]:0),carry=z[i]>=base;if(carry)z[i]-=base;
}else if(other!=0) {*this-=-other;}return*this;
}
friend Big operator+(Big a,const Big &b){a+=b; return a;}
Big &operator-=(const Big &other){
if(sign==other.sign){
if((sign==1&&*this>=other)||(sign==-1&&*this<=other)){
for(int i=0,carry=0;i<(int)other.z.size()||carry;++i){
z[i]-=carry+(i<(int)other.z.size()?other.z[i]:0),carry=z[i]<0;
if(carry) z[i]+=base;
}
trim();
} else *this=other-*this,this->sign=-this->sign;
} else {*this+=-other;}return*this;
}
friend Big operator-(Big a,const Big &b) {a-=b; return a;}
Big &operator*=(int v){
if(v<0) sign=-sign,v=-v;
for (int i=0,carry=0;i<(int)z.size()||carry;++i){
if(i==(int)z.size()) z.push_back(0);
long long cur=(long long)z[i]*v+carry;
carry=(int)(cur/base);z[i]=(int)(cur%base);
}
trim(); return*this;
}
Big operator*(int v)const{return Big(*this)*=v;}
friend pair<Big,Big>divmod(const Big&a1,const Big&b1) {
int norm=base/(b1.z.back()+1);
Big a=a1.abs()*norm,b=b1.abs()*norm,q,r; q.z.resize(a.z.size());
for(int i=(int)a.z.size()-1;i>=0;i--) {
r*=base,r+=a.z[i];
int s1=b.z.size()<r.z.size()?r.z[b.z.size()]:0,s2=b.z.size()-1<r.z.size()?r.z[b.z.size()-1]:0;
int d=(int)(((long long)s1*base+s2)/b.z.back());
r-=b*d;while(r<0)r+=b,--d;q.z[i]=d;
}
q.sign=a1.sign*b1.sign,r.sign=a1.sign;
q.trim(),r.trim(); return {q,r/norm};
}
friend Big sqrt(const Big&a1){
Big a=a1;
while(a.z.empty()||a.z.size()%2==1) a.z.push_back(0);
int n=a.z.size(),firstDigit=(int)::sqrt((double)a.z[n-1]*base+a.z[n-2]),norm=base/(firstDigit+1);
a*=norm,a*=norm; while(a.z.empty()||a.z.size()%2==1) a.z.push_back(0);
Big r=(long long)a.z[n-1]*base+a.z[n-2],res;
firstDigit=(int)::sqrt((double)a.z[n-1]*base+a.z[n-2]); int q=firstDigit;
for(int j=n/2-1;j>=0;j--){
for(;;--q){
Big r1=(r-(res*2*base+q)*q)*base*base+(j>0?(long long)a.z[2*j-1]*base+a.z[2*j-2]:0);
if(r1>=0){r=r1; break;}
}
res*=base;res+=q;
if(j>0){
int d1=res.z.size()+2<r.z.size()?r.z[res.z.size()+2]:0;
int d2=res.z.size()+1<r.z.size()?r.z[res.z.size()+1]:0;
int d3=res.z.size()<r.z.size()?r.z[res.z.size()]:0;
q=(int)(((long long)d1*base*base+(long long)d2*base+d3)/(firstDigit*2));
}
}
res.trim(); return res/norm;
}
Big operator/(const Big&v)const{return divmod(*this,v).first;}
Big operator%(const Big&v)const{return divmod(*this,v).second;}
Big &operator/=(int v){
if(v<0) sign=-sign,v=-v;
for(int i=(int)z.size()-1,rem=0;i>=0;--i){
long long cur=z[i]+rem*(long long)base;
z[i]=(int)(cur/v),rem=(int)(cur%v);
}
trim();return*this;
}
Big operator/(int v)const{return Big(*this)/=v;}
int operator%(int v) const {
if(v<0) v=-v; int m=0; for(int i=(int)z.size()-1;i>=0;--i) m=(int)((z[i]+m*(long long)base)%v);
return m*sign;
}
Big&operator*=(const Big &v){*this=*this*v; return*this;}
Big&operator/=(const Big &v){*this=*this/v; return*this;}
Big&operator%=(const Big &v){*this=*this%v; return*this;}
friend bool operator<(const Big &u,const Big &v){
if(u.sign!=v.sign) return u.sign<v.sign; if(u.z.size()!=v.z.size()) return u.z.size()*u.sign<v.z.size()*v.sign;
for(int i=(int)u.z.size()-1;i>=0;i--) if(u.z[i]!=v.z[i]) return u.z[i]*u.sign<v.z[i]*v.sign;
return false;
}
friend bool operator>(const Big &u,const Big &v){return v<u;}
friend bool operator<=(const Big &u,const Big &v){return !(v<u);}
friend bool operator>=(const Big &u,const Big &v){return !(u<v);}
friend bool operator==(const Big &u,const Big &v){return u.sign==v.sign&&u.z==v.z;}
friend bool operator!=(const Big &u,const Big &v){return !(u==v);}
void trim(){while(!z.empty()&&z.back()==0) z.pop_back(); if(z.empty()) sign=1;}
bool isZero()const{return z.empty();}
friend Big operator-(Big v){if(!v.z.empty()) v.sign=-v.sign; return v;}
Big abs()const{return sign==1?*this:-*this;}
long long to_num()const{
long long res=0;
for(int i=(int)z.size()-1;i>=0;i--) res=res*base+z[i];
return res*sign;
}
friend Big __gcd(const Big &a,const Big &b){return b.isZero()?a:__gcd(b,a%b);}
friend Big abs(const Big &a){return a.abs();}
void read(const string &s){
sign=1,z.clear(); int pos=0;
while(pos<(int)s.size()&&(s[pos]=='-'||s[pos]=='+')){if(s[pos]=='-') sign=-sign; ++pos;}
for(int i=(int)s.size()-1;i>=pos;i-=base_digits){
int x=0; for(int j=max(pos,i-base_digits+1);j<=i;j++) x=x*10+s[j]-'0';
z.push_back(x);
}
trim();
}
friend istream&operator>>(istream &stream,Big &v){string s; stream>>s; v.read(s); return stream;}
friend ostream&operator<<(ostream &stream,const Big &v){
if(v.sign==-1) stream<<'-'; stream<<(v.z.empty()?0:v.z.back());
for(int i=(int)v.z.size()-2; i>=0; --i) stream<<setw(base_digits)<<setfill('0')<<v.z[i];
return stream;
}
static vector<int>convert_base(const vector<int>&a,int old_digits,int new_digits){
vector<long long> p(max(old_digits,new_digits)+1);
p[0]=1; for(int i=1;i<(int)p.size();i++) p[i]=p[i-1]*10;
vector<int> res; long long cur=0; int cur_digits=0;
for(int v:a) {
cur+=v*p[cur_digits],cur_digits+=old_digits;
while(cur_digits>=new_digits)
res.push_back(int(cur%p[new_digits])),cur/=p[new_digits],cur_digits -= new_digits;
}
res.push_back((int)cur); while(!res.empty()&&res.back()==0) res.pop_back();
return res;
}
Big operator*(const Big&v)const{
if(min(z.size(),v.z.size())<150) return mul_simple(v);
Big res;res.sign=sign*v.sign;
res.z=multiply_BIG(convert_base(z,base_digits,fft_base_digits),
convert_base(v.z,base_digits,fft_base_digits),fft_base);
res.z=convert_base(res.z,fft_base_digits,base_digits);
res.trim(); return res;
}
Big mul_simple(const Big&v)const{Big res;res.sign=sign*v.sign;res.z.resize(z.size()+v.z.size());
for(int i=0;i<(int)z.size();++i) if(z[i]) for(int j=0,carry=0;j<(int)v.z.size()||carry;++j){
long long cur=res.z[i+j]+(long long)z[i]*(j<(int)v.z.size()?v.z[j]:0)+carry;
carry=(int)(cur/base),res.z[i+j]=(int)(cur%base);
}
res.trim(); return res;
}
};
mt19937 rng(std::chrono::system_clock::now().time_since_epoch().count());
Big BIG_rnd(int n){string s; for(int i=0;i<n;i++){s+=uniform_int_distribution<int>('0','9')(rng);} return Big(s);}
} using BIG_num::Big;
可以像其他变量一样用 cin
和 cout
。
如 cin>>a>>b;
定义一个 \(a\): BIG a;
可以连续定义:
如 BIG a=2,b,c=3;
加减乘除和一般变量一样,支持 +=
一类的,支持比较大小,不支持 BIG 转 int 等,但反过来支持。
分数
template<class Int> class Frac{
public:
Int top,btm;
Frac(){top=0;btm=1;} Frac(Int x){top=x;btm=1;} Frac(Int x,Int y){assert(y!=0); top=x,btm=y; this->normalize();}
double to_num(){return (double)top/btm;}
friend inline Frac abs(const Frac& x){return Frac(ibs(x.top),x.btm);}
friend inline Frac Rec(const Frac& x){return Frac(x.btm,x.top);}
friend inline Frac operator-(const Frac& x){return Frac(-x.top,x.btm);}
Frac& operator++(){top+=btm; return *this;}
Frac& operator--(){top-=btm; return *this;}
Frac operator++(int){Frac x(top); top+=btm; return x;}
Frac operator--(int){Frac x(top); top-=btm; return x;}
Frac& operator+=(const Frac& x){
Int g=Gcd(btm,x.btm);
top=btm/g*x.top+x.btm/g*top,btm*=x.btm/g; this->normalize();
return *this;
}
Frac& operator-=(const Frac& x){return *this+=(-x);}
Frac& operator*=(const Frac& x){
Int g1=Gcd(ibs(top),x.btm),g2=Gcd(ibs(x.top),btm);
(top/=g1)*=x.top/g2;(btm/=g2)*=x.btm/g1;
return *this;
}
Frac& operator/=(const Frac& x){return *this*=Rec(x);}
Frac friend operator+(Frac x,const Frac& y){return x+=y;}
Frac friend operator-(Frac x,const Frac& y){return x-=y;}
Frac friend operator*(Frac x,const Frac& y){return x*=y;}
Frac friend operator/(Frac x,const Frac& y){return x/=y;}
#define logical_operator(op) bool operator op(const Frac<Int>& y){return (*this-y).top op 0;}
logical_operator(<) logical_operator(>) logical_operator(<=) logical_operator(>=) logical_operator(==)
#undef logical_operator
#define logical_operator(op) template<class U> bool operator op(U y){return (*this-Frac(y)).top op 0;}
logical_operator(<) logical_operator(>) logical_operator(<=) logical_operator(>=) logical_operator(==)
#undef logical_operator
#define logical_operator(op) template<class U> friend bool operator op(U x,const Frac& y){return (Frac(x)-y).top op 0;}
logical_operator(<) logical_operator(>) logical_operator(<=) logical_operator(>=) logical_operator(==)
#undef logical_operator
friend istream&operator>>(istream &stream,Frac &v){stream>>v.top>>v.btm; v.normalize(); return stream;}
friend ostream&operator<<(ostream &stream,const Frac &v){stream<<v.top<<'/'<<v.btm; return stream;}//在此更改输出格式
private:
inline Int Gcd(Int a,Int b){while(b) swap((a%=b),b); return a;}
Int ibs(const Int& a){return a<0?-a:a;}
inline void normalize(){Int g=Gcd(ibs(top),btm); top/=g,btm/=g;}
};
定义时要加分子分母类型,类型支持上面的高精。
如果一次性赋值分子分母,用括号括起来。
如 Frac<int> a(1,3),b=(2,4)
。
取模数
template<class T> class Modular{
public:
using Type = typename decay<decltype(T::val)>::type;
constexpr static Type mod(){return T::val;}
constexpr Modular():val(){};
template<class U> Modular(const U& x){val=normalize(x);}
template<class U> static Type normalize(const U& x) {
Type v=static_cast<Type>((-mod()<=x&&x<mod())?x:x%mod());
return (v<0)?v+mod():v;
}
const Type& operator()()const{return val;}
template<class U> explicit operator U()const{return static_cast<U>(val);}
Modular& operator+=(const Modular& other){if((val+=other.val)>=mod()) val-=mod(); return *this;}
Modular& operator-=(const Modular& other){if((val-=other.val)<0) val+=mod(); return *this;}
template<class U> Modular& operator+=(const U& other){return *this+=Modular(other);}
template<class U> Modular& operator-=(const U& other){return *this-=Modular(other);}
Modular& operator++(){if(!((++val)^mod())) val=0; return *this;}
Modular& operator--(){if(!((--val)^(-1))) val=mod()-1; return *this;}
Modular operator++(int){Modular result(*this); if(!((++val)^mod())) val=0; return result;}
Modular operator--(int){Modular result(*this); if(!((--val)^(-1))) val=mod()-1; return result;}
Modular operator-()const{return Modular(-val);}
template<class U=T>
typename enable_if<is_same<typename Modular<U>::Type,int>::value,Modular>::type& operator*=(const Modular& rhs){
val=normalize(static_cast<long long>(val)*static_cast<long long>(rhs.val));
return *this;
}
template<class U=T>
typename enable_if<is_same<typename Modular<U>::Type,long long>::value,Modular>::type& operator*=(const Modular& rhs) {
long long q=static_cast<long long>(static_cast<long double>(val)*rhs.val/mod());
val=normalize(val*rhs.val-q*mod()); return *this;
}
template<class U=T>
typename enable_if<!is_integral<typename Modular<U>::Type>::value,Modular>::type& operator*=(const Modular& rhs) {
val=normalize(val*rhs.val);
return *this;
}
Modular& operator/=(const Modular& other){return *this*=Modular(Inv(other.val,mod()));}
friend const Type& abs(const Modular& x){return x.val;}
template<class V> friend bool operator==(const Modular<V>& lhs,const Modular<V>& rhs){return lhs.val==rhs.val;}
template<class V,class U> friend bool operator==(const Modular<V>& lhs,U rhs){return lhs==Modular<V>(rhs);}
template<class V,class U> friend bool operator==(U lhs,const Modular<V>& rhs){return Modular<V>(lhs)==rhs;}
template<class V> friend bool operator!=(const Modular<V>& lhs,const Modular<V>& rhs){return !(lhs==rhs);}
template<class V,class U> friend bool operator!=(const Modular<V>& lhs,U rhs){return !(lhs==rhs);}
template<class V,class U> friend bool operator!=(U lhs,const Modular<V>& rhs){return !(lhs==rhs);}
template<class V> friend bool operator<(const Modular<V>& lhs,const Modular<V>& rhs){return lhs.val<rhs.val;}
template<class V,class U> friend bool operator<(const Modular<V>& lhs,U rhs){return lhs<Modular<V>(rhs);}
template<class V,class U> friend bool operator<(U lhs,const Modular<V>& rhs){return Modular<V>(lhs)<rhs;}
template<class V> friend bool operator<=(const Modular<V>& lhs,const Modular<V>& rhs){return lhs.val<=rhs.val;}
template<class V,class U> friend bool operator<=(const Modular<V>& lhs,U rhs){return lhs<=Modular<V>(rhs);}
template<class V,class U> friend bool operator<=(U lhs,const Modular<V>& rhs){return Modular<V>(lhs)<=rhs;}
template<class V> friend bool operator>(const Modular<V>& lhs,const Modular<V>& rhs){return lhs.val>rhs.val;}
template<class V,class U> friend bool operator>(const Modular<V>& lhs,U rhs){return lhs>Modular<V>(rhs);}
template<class V,class U> friend bool operator>(U lhs,const Modular<V>& rhs){return Modular<V>(lhs)>rhs;}
template<class V> friend bool operator>=(const Modular<V>& lhs,const Modular<V>& rhs){return lhs.val>=rhs.val;}
template<class V,class U> friend bool operator>=(const Modular<V>& lhs,U rhs){return lhs>=Modular<V>(rhs);}
template<class V,class U> friend bool operator>=(U lhs,const Modular<V>& rhs){return Modular<V>(lhs)>=rhs;}
template<class V> friend Modular<V> operator+(const Modular<V>& lhs,const Modular<V>& rhs){return Modular<V>(lhs)+=rhs;}
template<class V,class U> friend Modular<V> operator+(const Modular<V>& lhs,U rhs){return Modular<V>(lhs)+=rhs;}
template<class V,class U> friend Modular<V> operator+(U lhs,const Modular<V>& rhs){return Modular<V>(lhs)+=rhs;}
template<class V> friend Modular<V> operator-(const Modular<V>& lhs,const Modular<V>& rhs){return Modular<V>(lhs)-=rhs;}
template<class V,class U> friend Modular<V> operator-(const Modular<V>& lhs,U rhs){return Modular<V>(lhs)-=rhs;}
template<class V,class U> friend Modular<V> operator-(U lhs,const Modular<V>& rhs){return Modular<V>(lhs)-=rhs;}
template<class V> friend Modular<V> operator*(const Modular<V>& lhs,const Modular<V>& rhs){return Modular<V>(lhs)*=rhs;}
template<class V,class U> friend Modular<V> operator*(const Modular<V>& lhs,U rhs){return Modular<V>(lhs)*=rhs;}
template<class V,class U> friend Modular<V> operator*(U lhs,const Modular<V>& rhs){return Modular<V>(lhs)*=rhs;}
template<class V> friend Modular<V> operator/(const Modular<V>& lhs,const Modular<V>& rhs){return Modular<V>(lhs)/=rhs;}
template<class V,class U> friend Modular<V> operator/(const Modular<V>& lhs,U rhs){return Modular<V>(lhs)/=rhs;}
template<class V,class U> friend Modular<V> operator/(U lhs,const Modular<V>& rhs){return Modular<V>(lhs)/=rhs;}
template<class V> friend string to_string(const Modular<V>& number){return to_string(number());}
template<class V> friend istream&operator>>(istream &stream,Modular<V>& v){
stream>>v.val; v.val=normalize(v.val); return stream;
}
template<class V> friend ostream&operator<<(ostream &stream,const Modular<V>& v){stream<<v(); return stream;}
private:
Type val;
template<class V> V Inv(const V& x,const V& m) {
assert(x!=0); V u=0,v=1,a=x,b=m,t;
while(a!=0) t=b/a,swap(a,b-=t*a),swap(u-=t*v,v);
assert(b==1); return u;
}
};
定义类似:
struct VarMod{static const int val=998244353;};
using Mint=Modular<VarMod>; // 固定模数
Mint a;
struct VarMod{static int val;};
int VarMod::val; int& MOD = VarMod::val;
using Mint=Modular<VarMod>; // 不固定模数,通过修改 MOD 改变模数
Mint a;
——————————————————————————————————————————————————————————————————————————————————————————————————————————
本文来自博客园,作者:xrlong,转载请注明原文链接:https://www.cnblogs.com/xrlong/articles/18050639