modint

所有乘法都用了快速乘,不用担心溢出了。
排列组合数都是 \(O(n)\),不用预处理,但常数变大了。
\(P\) 可以直接读入模数。


ll P=998244353;
ll O(ll x){return x<0?(x+=P):x<P?x:(x-=P);}
ll qmul(ll a,ll b,ll p=P) {
  ll rt=a*b-((ll)((ld)a/p*b))*p;
  return rt>=p?rt-p:rt<0?rt+p:rt;
}ll power(ll a,ll b,ll p=P){
  ll s=1;while(b){
    if(b&1) s=qmul(s,a,p);
    a=qmul(a,a,p);b>>=1;
  }return s;
}struct Z{
  ll x;Z(ll x=0):x(O(x%P)){}
  bool operator<(const Z&b)const{return x<b.x;}
  bool operator>(const Z&b)const{return x>b.x;}
  bool operator<=(const Z&b)const{return x<=b.x;}
  bool operator>=(const Z&b)const{return x>=b.x;}
  bool operator==(const Z&b)const{return x==b.x;}
  bool operator!=(const Z&b)const{return x!=b.x;}
  ll val()const{return x;}bool operator!(){return !x;}
  Z operator-()const{return Z(O(P-x));}
  Z&operator*=(const Z&r){x=qmul(x,r.x);return*this;}
  Z&operator+=(const Z&r){x=O(x+r.x);return*this;}
  Z&operator-=(const Z&r){x=O(x-r.x);return*this;}
  Z&operator/=(const Z&r){return*this*=r.inv();}
  Z&operator+=(const ll &r){x=O(x+r);return*this;}
  Z&operator-=(const ll &r){x=O(x-r);return*this;}
  Z&operator*=(const ll &r){x=qmul(x,r);return*this;}
  Z&operator/=(const ll &r){Z x=r;return*this*=x.inv();}
  friend Z operator*(const Z&l,const Z&r){Z s=l;s*=r;return s;}
  friend Z operator+(const Z&l,const Z&r){Z s=l;s+=r;return s;}
  friend Z operator-(const Z&l,const Z&r){Z s=l;s-=r;return s;}
  friend Z operator/(const Z&l,const Z&r){Z s=l;s/=r;return s;}
  friend Z operator*(const Z&l,const ll&r){Z s=l;s*=r;return s;}
  friend Z operator+(const Z&l,const ll&r){Z s=l;s+=r;return s;}
  friend Z operator-(const Z&l,const ll&r){Z s=l;s-=r;return s;}
  friend Z operator/(const Z&l,const ll&r){Z s=l;s/=r;return s;}
  Z &operator^=(ll b){return x=power(x,b),*this;}
  friend Z operator^(Z a,ll b){return a^=b;}
  Z inv()const{assert(x);return ((Z)x^(P-2));}
  friend istream&operator>>(istream&is,Z&a){ll v;is>>v;a=Z(v);return is;}
  friend ostream&operator<<(ostream&os,const Z&a){return os<<a.val();}
};vector<Z>jc,ijc,inv;
namespace math{
  void init(ll n){
    if(inv.empty()) jc=ijc=inv=vector<Z>(2,1);
    ll m=si(inv);++n;if(m>=n) return;
    L(i,m,n-1) inv.pb(inv[P%i]*(P-P/i)),
      jc.pb(jc[i-1]*i),ijc.pb(ijc[i-1]*inv[i]);
  }Z C(ll n,ll m){
    return init(n),m<0||n<m?0:jc[n]*ijc[m]*ijc[n-m];
  }Z A(ll n,ll m){
    return init(n),m<0||n<m?0:jc[n]*ijc[n-m];
  }Z BC(ll n,ll m){return m?BC(n/P,m/P)*C(n%P,m%P):1;}
  Z CAT(ll x){return C(2*x,x)-C(2*x,x+1);}
}using namespace math;

posted @ 2022-12-09 21:30  AIskeleton  阅读(21)  评论(0编辑  收藏  举报