luckYrat's library.

This documentation is automatically generated by competitive-verifier/competitive-verifier


:heavy_check_mark: cpp/z_test/aoj-NTL_2_F.test.cpp

Depends on

Required by

Code

#define PROBLEM "https://onlinejudge.u-aizu.ac.jp/courses/library/6/NTL/1/NTL_2_F"

#include "../../cpp/template/template.cpp"

#include "../../cpp/data-structure/big-int.cpp"

int main(){
  BigInt A,B;cin>>A>>B;
  cout << A*B << endl;
}
#line 1 "cpp/z_test/aoj-NTL_2_F.test.cpp"
#define PROBLEM "https://onlinejudge.u-aizu.ac.jp/courses/library/6/NTL/1/NTL_2_F"

#line 2 "cpp/template/template.cpp"

//yukicoder@cpp17

#include <iostream>
#include <iomanip>

#include <algorithm>

#include <cmath>
#include <cctype>
#include <climits>
#include <cassert>

#include <string>
#include <vector>
#include <set>
#include <stack>
#include <queue>
#include <map>

#include <random>

#include <bitset>

#include <complex>

#include <utility>

#include <numeric>

#include <functional>


using namespace std;
using ll = long long;
using P = pair<ll,ll>;


const ll MOD = 998244353;
const ll MODx = 1000000007;
const int INF = (1<<30)-1;
const ll LINF = (1LL<<62LL)-1;
const double EPS = (1e-10);


P ar4[4] = {{0,1},{0,-1},{1,0},{-1,0}};
P ar8[8] = {{-1,-1},{-1,0},{-1,1},{0,-1},{0,1},{1,-1},{1,0},{1,1}};


template <typename T> vector<T> make_vector(size_t a, T b) { return vector<T>(a, b); }
template <typename... Ts> auto make_vector(size_t a, Ts... ts) { return vector<decltype(make_vector(ts...))>(a, make_vector(ts...)); }
 
/*
確認ポイント
cout << fixed << setprecision(n) << 小数計算//n桁の小数表記になる

計算量は変わらないが楽できるシリーズ
min(max)_element(iter,iter)で一番小さい(大きい)値のポインタが帰ってくる
count(iter,iter,int)でintがiterからiterの間にいくつあったかを取得できる
*/

/* comment outed because can cause bugs
__attribute__((constructor))
void initial() {
  cin.tie(0);
  ios::sync_with_stdio(false);
}
*/
#line 4 "cpp/z_test/aoj-NTL_2_F.test.cpp"

#line 1 "cpp/math/convolution.cpp"
// Ref: https://qiita.com/AngrySadEight/items/0dfde26060daaf6a2fda

#line 2 "cpp/math/binary-power-method.cpp"

template <typename T>
T uPow(T z,T n, T mod){
  T ans = 1;
  while(n != 0){
    if(n%2){
      ans*=z;
      if(mod)ans%=mod;
    }
    n >>= 1;
    z*=z;
    if(mod)z%=mod;
  }
  return ans;
}

#line 2 "cpp/data-structure/mod-int/mod-int.cpp"

template <int mod>
struct ModInt{
  int n;
  ModInt():n(0){}
  ModInt(long long n_):n(n_ >= 0 ? n_%mod : mod - ((-n_)%mod) ){}
  ModInt(int n_):n(n_ >= 0 ? n_%mod : mod - ((-n_)%mod) ){}

  ModInt &operator+=(const ModInt &p){
    if((n+=p.n) >= mod)n-=mod;
    return *this;
  }
  ModInt &operator-=(const ModInt &p){
    n+=mod-p.n;
    if(n >= mod)n-=mod;
    return *this;
  }
  ModInt &operator*=(const ModInt &p){
    n = (int) ((1LL*n*p.n)%mod);
    return *this;
  }
  ModInt &operator/=(const ModInt &p){
    *this *= p.inverse();
    return *this;
  }
  ModInt operator-() const {return ModInt(-n);}
  ModInt operator+(const ModInt &p) const {return ModInt(*this) += p;}
  ModInt operator-(const ModInt &p) const {return ModInt(*this) -= p;}
  ModInt operator*(const ModInt &p) const {return ModInt(*this) *= p;}
  ModInt operator/(const ModInt &p) const {return ModInt(*this) /= p;}

  bool operator==(const ModInt &p) const {return n==p.n;}
  bool operator<(const ModInt &p) const {return n<p.n;}
  bool operator>(const ModInt &p) const {return n>p.n;}
  bool operator>=(const ModInt &p) const {return n>=p.n;}
  bool operator<=(const ModInt &p) const {return n<=p.n;}
  bool operator!=(const ModInt &p) const {return n!=p.n;}

  ModInt inverse() const {
    int a = n,b = mod,u = 1,v = 0;
    while(b){
      int t = a/b;
      a -= t*b; swap(a,b);
      u -= t*v; swap(u,v);
    }
    return ModInt(u);
  }

  ModInt pow(int64_t z) const {
    ModInt ret(1),mul(n);
    while(z > 0){
      if(z & 1) ret *= mul;
      mul *= mul;
      z >>= 1;
    }
    return ret;
  }

  int getMod() const {
    return mod;
  }

  friend ostream &operator<<(ostream &os, const ModInt &p){
    return os << p.n;
  }
  friend istream &operator>>(istream &is, ModInt &a){
    int64_t t;
    is >> t;
    a = ModInt<mod> ((long long)t);
    return (is);

  }
};
using mint = ModInt<MOD>;
#line 5 "cpp/math/convolution.cpp"
using namespace std;

template<typename MINT>
vector<MINT> ntt(vector<MINT> X, int depth, vector<MINT> root) {
  long long n = X.size();
  if(n == 1){
    return X;
  }else{
    vector<MINT> val(0);
    vector<MINT> even(0);
    vector<MINT> odd(0);
    for(int i = 0; n > i; i++){
      if(i % 2 == 0)even.push_back(X[i]);
      else odd.push_back(X[i]);
    }

    auto ntt_even = ntt(even, depth-1, root);
    auto ntt_odd = ntt(odd, depth-1, root);

    mint r = root[depth];

    MINT now = 1;
    for(int i = 0; n > i; i++){
      val.push_back(ntt_even[i%(n/2)] + (now * ntt_odd[i%(n/2)]));
      now *= r;
    }
    return val;
  }
}

template<typename MINT> // 998244353 mod
vector<MINT> make_root(long long p){
  vector<MINT> val(0);
  mint r = uPow(3LL, 119LL, p);
  for(int i = 0; 23 > i; i++){
    val.push_back(r);
    r *= r;
  }
  reverse(val.begin(), val.end());
  return val;
}

template<typename MINT>
vector<MINT> make_invroot(vector<MINT> root){
  vector<MINT> val(0);
  for(int i = 0; 23 > i; i++){
    val.push_back(root[i].inverse());
  }
  return val;
}

template<typename MINT>
vector<MINT> convolution(vector<MINT> A, vector<MINT> B){
  long long p = A[0].getMod(); // each mod must be same

  vector<MINT> root = make_root<MINT>(p);
  vector<MINT> invroot = make_invroot<MINT>(root);

  size_t size = (A.size()+B.size()-1);
  int n = 1;
  int log2_n = 0;
  while(n < size){
    n *= 2;
    log2_n++;
  }
  
  while(A.size() < n)A.push_back(0);
  while(B.size() < n)B.push_back(0);

  // AとBのNTTを求める
  auto nttA = ntt(A, log2_n-1, root);
  auto nttB = ntt(B, log2_n-1, root);

  vector<MINT> nttC(n);
  for(int i = 0; n > i; i++){
    nttC[i] = nttA[i]*nttB[i];
  }

  auto nC = ntt(nttC, log2_n-1, invroot);
  vector<MINT> C(size);
  for(int i = 0; size > i; i++){
    C[i] = nC[i]/(mint)n;
  }

  return C;
}

#line 2 "cpp/data-structure/big-int.cpp"

struct BigInt{
  string val;
  BigInt():val("0"){}
  BigInt(string s){
    if(s == "0"){
      val = "0";
      return;
    }
    bool firstdigit = false;
    for(int i = 0; s.size() > i; i++){
      if('0' <= s[i] && s[i] <= '9'){
        if(!firstdigit && s[i] == '0')continue;
        firstdigit = true;
        val.push_back(s[i]);
      }else if(s[i] == '-' && val.empty()){
        val.push_back(s[i]);
      }else{
        val = "0";
        break;
      }
    }
  }
  BigInt(int n): val(to_string(n)){}

  BigInt abs(BigInt p) const {
    if(p.val[0] == '-'){
      p.val = p.val.substr(1,p.val.size()-1);
    }
    return p;
  }
  
  int size(){
    return (*this).val.length();
  }

  bool isZero(){
    int i = 0;
    if((*this).val[0] == '-')i = 1; 
    for(; (*this).size() > i; i++){
      if((*this).val[i] != '0')return false;
    }
    return true;
  }

  BigInt SignTurn(BigInt p) const {
    if(p.val[0] == '-'){
      p.val = p.val.substr(1,p.val.size()-1);
    }else{
      p.val = "-" + p.val;
    }
    return p;
  }
  BigInt max(BigInt a,BigInt b) const {
    if(a.val.size() > b.val.size()){
      return a;
    }else if(a.val.size() < b.val.size()){
      return b;
    }else{
      for(int i = 0; a.val.size()> i; i++){
        if(a.val[i] > b.val[i]){
          return a;
        }
        if(a.val[i] < b.val[i]){
          return b;
        }
      }
    }
    return a;
  }

  BigInt operator+(const BigInt &p) const {
    BigInt z = *this;
    BigInt k = p;
    if(z.val[0] == '-' && p.val[0] == '-'){
      return  SignTurn(abs(z)+abs(k));//(-123)+(-124) -> -((123)+(124))
    }else if(z.val[0] == '-'){
      return k-abs(z);//(-123)+(124) -> (124)-(123)
    }else if(p.val[0] == '-'){
      return (z)-abs(k);//(123)+(-124) -> (123)-(124)
    }else{
      //123 + 1234
      bool Mvup = false;
      string ret = "";
      if(z.val.size() < k.val.size()){
        swap(z,k);
      }
      //val.size() > k.val.size();
      for(int i = z.val.size()-1; 0 <= i; i--){
        if(z.val.size()-k.val.size() > i){
          //val[i]+Mvup
          ret.push_back(((z.val[i]-'0'+(Mvup?1:0))%10)+'0');
          Mvup = ((z.val[i]-'0'+(Mvup?1:0))>=10);
        }else{
          //val[i],k.val[i-(val.size()-k.val.size())]+Mvup
          ret.push_back(((z.val[i]-'0'+k.val[i-(z.val.size()-k.val.size())]-'0'+(Mvup?1:0))%10)+'0');
          Mvup = ((z.val[i]-'0'+k.val[i-(z.val.size()-k.val.size())]-'0'+(Mvup?1:0)) >= 10);
        }
      }
      if(Mvup)ret.push_back('1');
      reverse(ret.begin(),ret.end());
      if(ret.empty())ret.push_back('0');
      z.val = ret;
    }
    return z;

  }
  BigInt operator-(const BigInt &p) const {
    BigInt z = *this;
    BigInt k = p;
    if(z.val[0] == '-' && k.val[0] == '-'){
      return (z)+abs(k);//(-123)-(-123) -> (-123)+(123)
    }else if(z.val[0] == '-'){
      return (z)+SignTurn(k);//(-123)-(123) -> (-123)+(-123)
    }else if(k.val[0] == '-'){
      return abs(k)+(z);//(123)-(-123) -> (123)+(123)
    }else{
      string ret = "";
      //z >= k
      bool Mvdwn = false;
      bool minus = false;
      if(max((z),k) != z){
        minus = true;
        swap(z,k);
      }
      for(int i = z.val.size()-1; 0 <= i; i--){
        if(z.val.size() - k.val.size() > i){
          if(z.val[i]-'0' < (Mvdwn?1:0)){
            ret.push_back(10+z.val[i]-(Mvdwn?1:0));
            Mvdwn = true;
          }else{
            ret.push_back(z.val[i]-(Mvdwn?1:0));
            Mvdwn = false;
          }
        }else{
          if(z.val[i] < k.val[i-(z.val.size()-k.val.size())]+(Mvdwn?1:0)){
            ret.push_back(10+z.val[i]-(k.val[i-(z.val.size()-k.val.size())]+(Mvdwn?1:0)) + '0');
            Mvdwn = true;
          }else{
            ret.push_back(z.val[i]- (k.val[i-(z.val.size()-k.val.size())]+(Mvdwn?1:0)) + '0');
            Mvdwn = false;
          }
        }
      }
      while(ret[ret.size()-1] == '0' && ret.size() > 1)ret.pop_back();
      if(minus)ret.push_back('-');
      if(ret.empty())ret.push_back('0');
      reverse(ret.begin(),ret.end());
      z.val = ret;
    }
    return z;
  }
  BigInt operator*(const BigInt &p) const {
    BigInt z = *this;
    BigInt k = p;
    bool minus = false;
    if((z.val[0] == '-') + (p.val[0] == '-') == 1)minus = true;
    string Z = abs(z).val;
    string K = abs(k).val;

    vector<mint> Zz(Z.size());
    for(int i = 0; Z.size() > i; i++){
      Zz[i] = Z[Z.size()-i-1]-'0';
    }
    vector<mint> Kk(K.size());
    for(int i = 0; K.size() > i; i++){
      Kk[i] = K[K.size()-i-1]-'0';
    }

    auto Cc = convolution(Zz, Kk);
    vector<int> C(Cc.size());
    for(int i = 0; Cc.size() > i; i++){
      C[i] = Cc[i].n;
    }
    for(int i = 0; C.size() > i; i++){
      if(C[i] >= 10 && i+1 == C.size()){
        C.push_back(C[i]/10);
      }else if(C[i] >= 10){
        C[i+1] += C[i]/10;
      }
      C[i] = C[i]%10;
    }
    C.push_back(0);
    while(C.size() != 1 && C[C.size()-1] == 0)C.pop_back();
    bool isZero = (C.size() == 1 && C[0] == 0);
    string val;
    if(minus && !isZero)val.push_back('-');
    for(int i = 0; C.size() > i; i++){
      val.push_back(C[C.size()-i-1]+'0');
    }
    BigInt ans = (BigInt)val;
    return ans;
  }

  //Only N
  BigInt operator/(const BigInt &p) const {
    BigInt z = *this;
    BigInt k = p;
    assert(k != (BigInt)"0");
    bool minus = false;
    if((z.val[0] == '-') + (p.val[0] == '-') == 1)minus = true;
    string Z = abs(z).val;
    string K = abs(k).val;
    BigInt rem = (BigInt)"0";
    BigInt ans = (BigInt)"0";
    // z / k
    for(int i = 0; Z.size() > i; i++){
      rem = rem*(BigInt)"10" + (BigInt)(Z[i]-'0');
      int nw = 0;
      while(rem >= K){
        nw++;
        rem -= K;
      }
      ans = ans*(BigInt)"10" + (BigInt)(nw);
    }
    if(minus && !ans.isZero())ans = SignTurn(ans);
    return ans;
  }
  
  BigInt operator%(const BigInt &p) const {
    BigInt z = *this;
    BigInt k = p;
    assert(k != (BigInt)"0");
    bool minus = false;
    if((z.val[0] == '-') + (p.val[0] == '-') == 1)minus = true;
    string Z = abs(z).val;
    string K = abs(k).val;
    BigInt rem = (BigInt)"0";
    BigInt ans = (BigInt)"0";
    // z / k
    for(int i = 0; Z.size() > i; i++){
      rem = rem*(BigInt)"10" + (BigInt)(Z[i]-'0');
      int nw = 0;
      while(rem >= K){
        nw++;
        rem -= K;
      }
      ans = ans*(BigInt)"10" + (BigInt)(nw);
    }
    return rem;
  }

  BigInt operator+=(const BigInt &p){return *this = (*this) + p;}
  BigInt operator-=(const BigInt &p){return *this = (*this) - p;}
  BigInt operator*=(const BigInt &p){return *this = (*this) * p;}
  BigInt operator/=(const BigInt &p){return *this = (*this) / p;}
  BigInt operator%=(const BigInt &p){return *this = (*this) % p;}

  bool operator==(const BigInt &p)const{return val == p.val;}
  bool operator!=(const BigInt &p)const{return val != p.val;}
  bool operator<(const BigInt &p)const{return val != max(*this, p).val;}
  bool operator<=(const BigInt &p)const{return (*this) == p || (*this) < p;}
  bool operator>(const BigInt &p)const{return p.val != max(*this, p).val;}
  bool operator>=(const BigInt &p)const{return (*this) == p || (*this) > p;}
  

  friend ostream &operator<<(ostream &os, const BigInt &p){
    return os << p.val;
  }
  friend istream &operator>>(istream &is, BigInt &p){
    string s;
    cin>>s;
    p = BigInt(s);
    return (is);
  }
};

#line 6 "cpp/z_test/aoj-NTL_2_F.test.cpp"

int main(){
  BigInt A,B;cin>>A>>B;
  cout << A*B << endl;
}

Test cases

Env Name Status Elapsed Memory
g++ 00_sample_00.in :heavy_check_mark: AC 7 ms 3 MB
g++ 00_sample_01.in :heavy_check_mark: AC 6 ms 3 MB
g++ 00_sample_02.in :heavy_check_mark: AC 6 ms 4 MB
g++ 00_sample_03.in :heavy_check_mark: AC 6 ms 3 MB
g++ 01_minimum_00.in :heavy_check_mark: AC 6 ms 4 MB
g++ 01_minimum_01.in :heavy_check_mark: AC 5 ms 3 MB
g++ 01_minimum_02.in :heavy_check_mark: AC 6 ms 3 MB
g++ 01_minimum_03.in :heavy_check_mark: AC 6 ms 3 MB
g++ 02_random_00.in :heavy_check_mark: AC 6 ms 3 MB
g++ 02_random_01.in :heavy_check_mark: AC 6 ms 4 MB
g++ 02_random_02.in :heavy_check_mark: AC 6 ms 3 MB
g++ 02_random_03.in :heavy_check_mark: AC 6 ms 4 MB
g++ 03_random_00.in :heavy_check_mark: AC 6 ms 3 MB
g++ 03_random_01.in :heavy_check_mark: AC 6 ms 3 MB
g++ 03_random_02.in :heavy_check_mark: AC 6 ms 3 MB
g++ 03_random_03.in :heavy_check_mark: AC 6 ms 3 MB
g++ 03_random_04.in :heavy_check_mark: AC 6 ms 4 MB
g++ 03_random_05.in :heavy_check_mark: AC 6 ms 3 MB
g++ 03_random_06.in :heavy_check_mark: AC 6 ms 3 MB
g++ 03_random_07.in :heavy_check_mark: AC 7 ms 4 MB
g++ 03_random_08.in :heavy_check_mark: AC 6 ms 3 MB
g++ 03_random_09.in :heavy_check_mark: AC 6 ms 3 MB
g++ 03_random_10.in :heavy_check_mark: AC 6 ms 4 MB
g++ 04_large_00.in :heavy_check_mark: AC 6 ms 4 MB
g++ 04_large_01.in :heavy_check_mark: AC 7 ms 4 MB
g++ 04_large_02.in :heavy_check_mark: AC 6 ms 4 MB
g++ 04_large_03.in :heavy_check_mark: AC 7 ms 4 MB
g++ 04_large_04.in :heavy_check_mark: AC 7 ms 3 MB
g++ 04_large_05.in :heavy_check_mark: AC 7 ms 4 MB
g++ 04_large_06.in :heavy_check_mark: AC 7 ms 3 MB
g++ 05_maximum_00.in :heavy_check_mark: AC 291 ms 16 MB
g++ 05_maximum_01.in :heavy_check_mark: AC 290 ms 16 MB
g++ 05_maximum_02.in :heavy_check_mark: AC 589 ms 32 MB
g++ 05_maximum_03.in :heavy_check_mark: AC 593 ms 32 MB
g++ 05_maximum_04.in :heavy_check_mark: AC 291 ms 16 MB
g++ 05_maximum_05.in :heavy_check_mark: AC 294 ms 16 MB
g++ 05_maximum_06.in :heavy_check_mark: AC 585 ms 31 MB
g++ 05_maximum_07.in :heavy_check_mark: AC 584 ms 31 MB
g++ 06_corner_00.in :heavy_check_mark: AC 7 ms 4 MB
g++ 06_corner_01.in :heavy_check_mark: AC 6 ms 3 MB
g++ 06_corner_02.in :heavy_check_mark: AC 6 ms 3 MB
g++ 06_corner_03.in :heavy_check_mark: AC 5 ms 4 MB
g++ 07_maximum_corner_00.in :heavy_check_mark: AC 287 ms 16 MB
g++ 07_maximum_corner_01.in :heavy_check_mark: AC 290 ms 16 MB
g++ 07_maximum_corner_02.in :heavy_check_mark: AC 599 ms 32 MB
g++ 07_maximum_corner_03.in :heavy_check_mark: AC 586 ms 31 MB
g++ 07_maximum_corner_04.in :heavy_check_mark: AC 288 ms 16 MB
g++ 07_maximum_corner_05.in :heavy_check_mark: AC 291 ms 16 MB
g++ 07_maximum_corner_06.in :heavy_check_mark: AC 593 ms 31 MB
g++ 07_maximum_corner_07.in :heavy_check_mark: AC 597 ms 31 MB
Back to top page