Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include<bits/stdc++.h>
- using namespace std;
- using ll = long long;
- using ld = long double;
- using ull = unsigned long long;
- using pii = pair<int, int>;
- using pll = pair<ll, ll>;
- using pld = pair<ld, ld>;
- #define fi first
- #define se second
- #define left BAO
- #define right ANH
- #define pb push_back
- #define pf push_front
- #define mp make_pair
- #define ins insert
- #define btpc __builtin_popcount
- #define btclz __builtin_clz
- #define sz(x) (int)(x.size());
- #define all(x) x.begin(), x.end()
- #define debug(...) " [" << #__VA_ARGS__ ": " << (__VA_ARGS__) << "] "
- mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
- int d4x[4] = {1, 0, -1, 0}; int d4y[4] = {0, 1, 0, -1};
- int d8x[8] = {0, 1, 1, 1, 0, -1, -1, -1};
- int d8y[8] = {1, 1, 0, -1, -1, -1, 0, 1};
- template<class X, class Y>
- bool minimize(X &x, const Y &y) {
- if (x > y)
- {
- x = y;
- return true;
- }
- return false;
- }
- template<class X, class Y>
- bool maximize(X &x, const Y &y) {
- if (x < y)
- {
- x = y;
- return true;
- }
- return false;
- }
- const int MOD = 1e9 + 7; //998244353
- template<class X, class Y>
- void add(X &x, const Y &y) {
- x = (x + y);
- if(x >= MOD) x -= MOD;
- }
- template<class X, class Y>
- void sub(X &x, const Y &y) {
- x = (x - y);
- if(x < 0) x += MOD;
- }
- /* Author : Le Ngoc Bao Anh, 12A5, LQD High School for Gifted Student*/
- const ll INF = 1e9;
- const int N = 1e7 + 10;
- template <typename T> T mod_inv_in_range(T a, T m) {
- // assert(0 <= a && a < m);
- T x = a, y = m;
- T vx = 1, vy = 0;
- while (x) {
- T k = y / x;
- y %= x;
- vy -= k * vx;
- std::swap(x, y);
- std::swap(vx, vy);
- }
- assert(y == 1);
- return vy < 0 ? m + vy : vy;
- }
- template <typename T> T mod_inv(T a, T m) {
- a %= m;
- a = a < 0 ? a + m : a;
- return mod_inv_in_range(a, m);
- }
- template <int MOD_> struct modnum {
- static constexpr int MOD = MOD_;
- static_assert(MOD_ > 0, "MOD must be positive");
- using ll = long long;
- int v;
- public:
- modnum() : v(0) {}
- modnum(ll v_) : v(int(v_ % MOD)) { if (v < 0) v += MOD; }
- explicit operator int() const { return v; }
- friend std::ostream& operator << (std::ostream& out, const modnum& n) { return out << int(n); }
- friend std::istream& operator >> (std::istream& in, modnum& n) { ll v_; in >> v_; n = modnum(v_); return in; }
- friend bool operator == (const modnum& a, const modnum& b) { return a.v == b.v; }
- friend bool operator != (const modnum& a, const modnum& b) { return a.v != b.v; }
- modnum inv() const {
- modnum res;
- res.v = mod_inv_in_range(v, MOD);
- return res;
- }
- friend modnum inv(const modnum& m) { return m.inv(); }
- modnum neg() const {
- modnum res;
- res.v = v ? MOD-v : 0;
- return res;
- }
- friend modnum neg(const modnum& m) { return m.neg(); }
- modnum operator- () const {
- return neg();
- }
- modnum operator+ () const {
- return modnum(*this);
- }
- modnum& operator ++ () {
- v ++;
- if (v == MOD) v = 0;
- return *this;
- }
- modnum& operator -- () {
- if (v == 0) v = MOD;
- v --;
- return *this;
- }
- modnum& operator += (const modnum& o) {
- v -= MOD-o.v;
- v = (v < 0) ? v + MOD : v;
- return *this;
- }
- modnum& operator -= (const modnum& o) {
- v -= o.v;
- v = (v < 0) ? v + MOD : v;
- return *this;
- }
- modnum& operator *= (const modnum& o) {
- v = int(ll(v) * ll(o.v) % MOD);
- return *this;
- }
- modnum& operator /= (const modnum& o) {
- return *this *= o.inv();
- }
- friend modnum operator ++ (modnum& a, int) { modnum r = a; ++a; return r; }
- friend modnum operator -- (modnum& a, int) { modnum r = a; --a; return r; }
- friend modnum operator + (const modnum& a, const modnum& b) { return modnum(a) += b; }
- friend modnum operator - (const modnum& a, const modnum& b) { return modnum(a) -= b; }
- friend modnum operator * (const modnum& a, const modnum& b) { return modnum(a) *= b; }
- friend modnum operator / (const modnum& a, const modnum& b) { return modnum(a) /= b; }
- };
- //ctto
- typedef complex<ld> pt;
- const ld PI = acos(-1.L);
- template<class T> struct cplx {
- T x, y;
- cplx() {
- x = 0.0;
- y = 0.0;
- }
- cplx(T nx, T ny = 0) {
- x = nx;
- y = ny;
- }
- cplx operator+(const cplx &c) const {
- return {x + c.x, y + c.y};
- }
- cplx operator-(const cplx &c) const {
- return {x - c.x, y - c.y};
- }
- cplx operator*(const cplx &c) const {
- return {x*c.x - y * c.y, x*c.y + y * c.x};
- }
- cplx& operator*=(const cplx &c) {
- return *this = {x*c.x - y * c.y, x*c.y + y * c.x};
- }
- inline T real() const {
- return x;
- }
- inline T imag() const {
- return y;
- }
- // Only supports right scalar multiplication like p*c
- template<class U> cplx operator*(const U &c) const {
- return {x * c, y * c};
- }
- template<class U> cplx operator/(const U &c) const {
- return {x / c, y / c};
- }
- template<class U> void operator/=(const U &c) {
- x /= c;
- y /= c;
- }
- };
- #define polar(r,a) (cplx<ld>){r*cos(a),r*sin(a)}
- const int DIG = 9, FDIG = 4;
- const int BASE = 1e9, FBASE = 1e4;
- typedef cplx<ld> Cplx;
- // use mulmod when taking mod by int v and v>2e9
- // you can use mod by BigNum in that case too
- struct BigNum {
- int sgn;
- vector<int> a;
- BigNum() : sgn(1) {}
- BigNum(ll v) {
- *this = v;
- }
- BigNum& operator = (ll v) {
- sgn = 1;
- if (v < 0) sgn = -1, v = -v;
- a.clear();
- for (; v > 0; v /= BASE) a.push_back(v % BASE);
- return *this;
- }
- BigNum(const BigNum& other) {
- sgn = other.sgn;
- a = other.a;
- }
- friend void swap(BigNum& a, BigNum& b) {
- swap(a.sgn, b.sgn);
- swap(a.a, b.a);
- }
- BigNum& operator = (BigNum other) {
- swap(*this, other);
- return *this;
- }
- BigNum(BigNum&& other) : BigNum() {
- swap(*this, other);
- }
- BigNum(const string& s) {
- read(s);
- }
- void read(const string& s) {
- sgn = 1;
- a.clear();
- int k = 0;
- for (; k < s.size() && (s[k] == '-' || s[k] == '+'); k++)
- if (s[k] == '-') sgn = -sgn;
- for (int i = s.size() - 1; i >= k; i -= DIG) {
- int x = 0;
- for (int j = max(k, i - DIG + 1); j <= i; j++) x = x * 10 + s[j] - '0';
- a.push_back(x);
- }
- trim();
- }
- friend istream& operator>>(istream &in, BigNum &v) {
- string s;
- in >> s;
- v.read(s);
- return in;
- }
- friend ostream& operator<<(ostream &out, const BigNum &v) {
- if (v.sgn == -1 && !v.zero()) out << '-';
- out << (v.a.empty() ? 0 : v.a.back());
- for (int i = (int) v.a.size() - 2; i >= 0; --i)
- out << setw(DIG) << setfill('0') << v.a[i];
- return out;
- }
- bool operator<(const BigNum &v) const {
- if (sgn != v.sgn) return sgn < v.sgn;
- if (a.size() != v.a.size()) return a.size() * sgn < v.a.size() * v.sgn;
- for (int i = (int)a.size() - 1; i >= 0; i--)
- if (a[i] != v.a[i]) return a[i] * sgn < v.a[i] * sgn;
- return 0;
- }
- bool operator>(const BigNum &v) const {
- return v < *this;
- }
- bool operator<=(const BigNum &v) const {
- return !(v < *this);
- }
- bool operator>=(const BigNum &v) const {
- return !(*this < v);
- }
- bool operator==(const BigNum &v) const {
- return !(*this < v) && !(v < *this);
- }
- bool operator!=(const BigNum &v) const {
- return *this < v || v < *this;
- }
- friend int __cmp(const BigNum& x, const BigNum& y) {
- if (x.a.size() != y.a.size()) return x.a.size() < y.a.size() ? -1 : 1;
- for (int i = (int) x.a.size() - 1; i >= 0; --i) if (x.a[i] != y.a[i])
- return x.a[i] < y.a[i] ? -1 : 1;
- return 0;
- }
- BigNum operator-() const {
- BigNum res = *this;
- if (zero()) return res;
- res.sgn = -sgn;
- return res;
- }
- void __add(const BigNum& v) {
- if (a.size() < v.a.size()) a.resize(v.a.size(), 0);
- for (int i = 0, carry = 0; i < max(a.size(), v.a.size()) || carry; ++i) {
- if (i == a.size()) a.push_back(0);
- a[i] += carry + (i < (int) v.a.size() ? v.a[i] : 0);
- carry = a[i] >= BASE;
- if (carry) a[i] -= BASE;
- }
- }
- void __sub(const BigNum& v) {
- for (int i = 0, carry = 0; i < (int) v.a.size() || carry; ++i) {
- a[i] -= carry + (i < (int) v.a.size() ? v.a[i] : 0);
- carry = a[i] < 0;
- if (carry) a[i] += BASE;
- }
- this->trim();
- }
- BigNum operator+=(const BigNum& v) {
- if (sgn == v.sgn) __add(v);
- else if (__cmp(*this, v) >= 0) __sub(v);
- else {
- BigNum vv = v;
- swap(*this, vv);
- __sub(vv);
- }
- return *this;
- }
- BigNum operator-=(const BigNum& v) {
- if (sgn == v.sgn) {
- if (__cmp(*this, v) >= 0) __sub(v);
- else {
- BigNum vv = v;
- swap(*this, vv);
- __sub(vv);
- sgn = -sgn;
- }
- } else __add(v);
- return *this;
- }
- template< typename L, typename R >
- typename enable_if <
- is_convertible<L, BigNum>::value &&
- is_convertible<R, BigNum>::value &&
- is_lvalue_reference < R&& >::value,
- BigNum >::type friend operator + (L&& l, R&& r) {
- BigNum result(forward<L>(l));
- result += r;
- return result;
- }
- template< typename L, typename R >
- typename enable_if <
- is_convertible<L, BigNum>::value &&
- is_convertible<R, BigNum>::value &&
- is_rvalue_reference < R&& >::value,
- BigNum >::type friend operator + (L&& l, R&& r) {
- BigNum result(move(r));
- result += l;
- return result;
- }
- template< typename L, typename R >
- typename enable_if <
- is_convertible<L, BigNum>::value &&
- is_convertible<R, BigNum>::value,
- BigNum >::type friend operator - (L&& l, R&& r) {
- BigNum result(forward<L>(l));
- result -= r;
- return result;
- }
- friend pair<BigNum, BigNum> divmod(const BigNum& a1, const BigNum& b1) {
- ll norm = BASE / (b1.a.back() + 1);
- BigNum a = a1.abs() * norm, b = b1.abs() * norm, q = 0, r = 0;
- q.a.resize(a.a.size());
- for (int i = a.a.size() - 1; i >= 0; i--) {
- r *= BASE;
- r += a.a[i];
- ll s1 = r.a.size() <= b.a.size() ? 0 : r.a[b.a.size()];
- ll s2 = r.a.size() <= b.a.size() - 1 ? 0 : r.a[b.a.size() - 1];
- ll d = ((ll) BASE * s1 + s2) / b.a.back();
- r -= b * d;
- while (r < 0) r += b, --d;
- q.a[i] = d;
- }
- q.sgn = a1.sgn * b1.sgn;
- r.sgn = a1.sgn;
- q.trim();
- r.trim();
- auto res = make_pair(q, r / norm);
- if (res.second < 0) res.second += b1;
- return res;
- }
- BigNum operator/(const BigNum &v) const {
- return divmod(*this, v).first;
- }
- BigNum operator%(const BigNum &v) const {
- return divmod(*this, v).second;
- }
- void operator/=(int v) {
- if (llabs(v) >= BASE) {
- *this /= BigNum(v);
- return;
- }
- if (v < 0) sgn = -sgn, v = -v;
- for (int i = (int) a.size() - 1, rem = 0; i >= 0; --i) {
- ll cur = a[i] + rem * (ll)BASE;
- a[i] = (int) (cur / v);
- rem = (int) (cur % v);
- }
- trim();
- }
- BigNum operator/(int v) const {
- if (llabs(v) >= BASE) return *this / BigNum(v);
- BigNum res = *this;
- res /= v;
- return res;
- }
- void operator/=(const BigNum &v) {
- *this = *this / v;
- }
- ll operator%(ll v) const {
- int m = 0;
- for (int i = a.size() - 1; i >= 0; --i) m = (a[i] + m * (ll) BASE) % v;
- return m * sgn;
- }
- void operator*=(int v) {
- if (llabs(v) >= BASE) {
- *this *= BigNum(v);
- return;
- }
- if (v < 0) sgn = -sgn, v = -v;
- for (int i = 0, carry = 0; i < a.size() || carry; ++i) {
- if (i == a.size()) a.push_back(0);
- ll cur = a[i] * (ll) v + carry;
- carry = (int) (cur / BASE);
- a[i] = (int) (cur % BASE);
- }
- trim();
- }
- BigNum operator*(int v) const {
- if (llabs(v) >= BASE) return *this * BigNum(v);
- BigNum res = *this;
- res *= v;
- return res;
- }
- static vector<int> convert_base(const vector<int> &a, int old_digits, int new_digits) {
- vector<ll> 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;
- ll cur = 0;
- int cur_digits = 0;
- for (int i = 0; i < (int) a.size(); i++) {
- cur += a[i] * p[cur_digits];
- cur_digits += old_digits;
- while (cur_digits >= new_digits) {
- res.push_back((ll)(cur % p[new_digits]));
- cur /= p[new_digits];
- cur_digits -= new_digits;
- }
- }
- res.push_back((int) cur);
- while (!res.empty() && !res.back())
- res.pop_back();
- return res;
- }
- void fft(vector<Cplx>& a, bool invert) const {
- int n = a.size();
- for (int i = 1, j = 0; i < n; ++i) {
- int bit = n / 2;
- for (; j >= bit; bit /= 2) j -= bit;
- j += bit;
- if (i < j) swap(a[i], a[j]);
- }
- for (int len = 2; len <= n; len *= 2) {
- ld ang = 2 * PI / len * (invert ? -1 : 1);
- Cplx wlen = polar(1, ang);
- for (int i = 0; i < n; i += len) {
- Cplx w(1);
- for (int j = 0; j < len / 2; ++j) {
- Cplx u = a[i + j], v = a[i + j + len / 2] * w;
- a[i + j] = u + v;
- a[i + j + len / 2] = u - v;
- w *= wlen;
- }
- }
- }
- if (invert) for (int i = 0; i < n; ++i) a[i] /= n;
- }
- void multiply_fft(const vector<int> &a, const vector<int> &b, vector<int> &res) const {
- vector<Cplx> fa(a.begin(), a.end()), fb(b.begin(), b.end());
- int n = 1;
- while (n < max(a.size(), b.size())) n *= 2;
- n *= 2;
- fa.resize(n);
- fb.resize(n);
- fft(fa, 0);
- fft(fb, 0);
- for (int i = 0; i < n; ++i) fa[i] *= fb[i];
- fft(fa, 1);
- res.resize(n);
- ll carry = 0;
- for (int i = 0; i < n; i++) {
- ll t = (ll)(fa[i].real() + 0.5) + carry;
- carry = t / FBASE;
- res[i] = t % FBASE;
- }
- }
- static inline int rev_incr(int a, int n) {
- int msk = n / 2, cnt = 0;
- while ( a & msk ) {
- cnt++;
- a <<= 1;
- }
- a &= msk - 1;
- a |= msk;
- while ( cnt-- ) a >>= 1;
- return a;
- }
- static vector<Cplx> FFT(vector<Cplx> v, int dir = 1) {
- Cplx wm, w, u, t;
- int n = v.size();
- vector<Cplx> V(n);
- for (int k = 0, a = 0; k < n; ++k, a = rev_incr(a, n))
- V[a] = v[k] / ld(dir > 0 ? 1 : n);
- for (int m = 2; m <= n; m <<= 1) {
- wm = polar( (ld)1, dir * 2 * PI / m );
- for (int k = 0; k < n; k += m) {
- w = 1;
- for (int j = 0; j < m / 2; ++j, w *= wm) {
- u = V[k + j];
- t = w * V[k + j + m / 2];
- V[k + j] = u + t;
- V[k + j + m / 2] = u - t;
- }
- }
- }
- return V;
- }
- static void convolution(const vector<int>& a, const vector<int>& b, vector<int>& c) {
- int sz = a.size() + b.size() - 1;
- int n = 1 << int(ceil(log2(sz)));
- vector<Cplx> av(n, 0), bv(n, 0), cv;
- for (int i = 0; i < a.size(); i++) av[i] = a[i];
- for (int i = 0; i < b.size(); i++) bv[i] = b[i];
- cv = FFT(bv);
- bv = FFT(av);
- for (int i = 0; i < n; i++) av[i] = bv[i] * cv[i];
- cv = FFT(av, -1);
- c.resize(n);
- ll carry = 0;
- for (int i = 0; i < n; i++) {
- ll t = ll(cv[i].real() + 0.5) + carry;
- carry = t / FBASE;
- c[i] = t % FBASE;
- }
- }
- BigNum mul_simple(const BigNum &v) const {
- BigNum res;
- res.sgn = sgn * v.sgn;
- res.a.resize(a.size() + v.a.size());
- for (int i = 0; i < a.size(); i++) if (a[i])
- for (int j = 0, carry = 0; j < v.a.size() || carry; j++) {
- ll cur = res.a[i + j] + (ll) a[i] * (j < v.a.size() ? v.a[j] : 0) + carry;
- carry = (int) (cur / BASE);
- res.a[i + j] = (int) (cur % BASE);
- }
- res.trim();
- return res;
- }
- BigNum mul_fft(const BigNum& v) const {
- BigNum res;
- convolution(convert_base(a, DIG, FDIG), convert_base(v.a, DIG, FDIG), res.a);
- res.a = convert_base(res.a, FDIG, DIG);
- res.trim();
- return res;
- }
- void operator*=(const BigNum &v) {
- *this = *this * v;
- }
- BigNum operator*(const BigNum &v) const {
- if (1LL * a.size() * v.a.size() <= 1000111) return mul_simple(v);
- return mul_fft(v);
- }
- BigNum abs() const {
- BigNum res = *this;
- res.sgn *= res.sgn;
- return res;
- }
- void trim() {
- while (!a.empty() && !a.back()) a.pop_back();
- }
- bool zero() const {
- return a.empty() || (a.size() == 1 && !a[0]);
- }
- friend BigNum gcd(const BigNum &a, const BigNum &b) {
- return b.zero() ? a : gcd(b, a % b);
- }
- };
- #define double long double
- namespace FFT {
- const int maxf = 1 << 17;
- struct cp {
- double x, y;
- cp(double x = 0, double y = 0) : x(x), y(y) {}
- cp operator + (const cp& rhs) const {
- return cp(x + rhs.x, y + rhs.y);
- }
- cp operator - (const cp& rhs) const {
- return cp(x - rhs.x, y - rhs.y);
- }
- cp operator * (const cp& rhs) const {
- return cp(x * rhs.x - y * rhs.y, x * rhs.y + y * rhs.x);
- }
- cp operator !() const {
- return cp(x, -y);
- }
- } rts[maxf + 1];
- cp fa[maxf], fb[maxf];
- cp fc[maxf], fd[maxf];
- int bitrev[maxf];
- void fftinit() {
- int k = 0; while ((1 << k) < maxf) k++;
- bitrev[0] = 0;
- for (int i = 1; i < maxf; i++) {
- bitrev[i] = bitrev[i >> 1] >> 1 | ((i & 1) << k - 1);
- }
- double PI = acos((double) -1.0);
- rts[0] = rts[maxf] = cp(1, 0);
- for (int i = 1; i + i <= maxf; i++) {
- rts[i] = cp(cos(i * 2 * PI / maxf), sin(i * 2 * PI / maxf));
- }
- for (int i = maxf / 2 + 1; i < maxf; i++) {
- rts[i] = !rts[maxf - i];
- }
- }
- void dft(cp a[], int n, int sign) {
- static int isinit;
- if (!isinit) {
- isinit = 1;
- fftinit();
- }
- int d = 0; while ((1 << d) * n != maxf) d++;
- for (int i = 0; i < n; i++) {
- if (i < (bitrev[i] >> d)) {
- swap(a[i], a[bitrev[i] >> d]);
- }
- }
- for (int len = 2; len <= n; len <<= 1) {
- int delta = maxf / len * sign;
- for (int i = 0; i < n; i += len) {
- cp *x = a + i,*y = a + i + (len >> 1), *w = sign > 0 ? rts : rts + maxf;
- for (int k = 0; k + k < len; k++) {
- cp z = *y * *w;
- *y = *x - z, *x = *x + z;
- x++, y++, w += delta;
- }
- }
- }
- if (sign < 0) {
- for (int i = 0; i < n; i++) {
- a[i].x /= n;
- a[i].y /= n;
- }
- }
- }
- void multiply(int a[], int b[], int na, int nb, long long c[], int dup = 0) {
- int n = na + nb - 1; while (n != (n & -n)) n += n & -n;
- for (int i = 0; i < n; i++) fa[i] = fb[i] = cp();
- for (int i = 0; i < na; i++) fa[i] = cp(a[i]);
- for (int i = 0; i < nb; i++) fb[i] = cp(b[i]);
- dft(fa, n, 1);
- if (dup) {
- for (int i = 0; i < n; i++) fb[i] = fa[i];
- }
- else {
- dft(fb, n, 1);
- }
- for (int i = 0; i < n; i++) fa[i] = fa[i] * fb[i];
- dft(fa, n, -1);
- for (int i = 0; i < n; i++) c[i] = (long long) floor(fa[i].x + 0.5);
- }
- void multiply(int a[], int b[], int na, int nb, int c[], int mod = (int) 1e9 + 7, int dup = 0) {
- int n = na + nb - 1;
- while (n != (n & -n)) n += n & -n;
- for (int i = 0; i < n; i++) fa[i] = fb[i] = cp();
- static const int magic = 15;
- for (int i = 0; i < na; i++) fa[i] = cp(a[i] >> magic, a[i] & (1 << magic) - 1);
- for (int i = 0; i < nb; i++) fb[i] = cp(b[i] >> magic, b[i] & (1 << magic) - 1);
- dft(fa, n, 1);
- if (dup) {
- for (int i = 0; i < n; i++) fb[i] = fa[i];
- }
- else {
- dft(fb, n, 1);
- }
- for (int i = 0; i < n; i++) {
- int j = (n - i) % n;
- cp x = fa[i] + !fa[j];
- cp y = fb[i] + !fb[j];
- cp z = !fa[j] - fa[i];
- cp t = !fb[j] - fb[i];
- fc[i] = (x * t + y * z) * cp(0, 0.25);
- fd[i] = x * y * cp(0, 0.25) + z * t * cp(-0.25, 0);
- }
- dft(fc, n, -1), dft(fd, n, -1);
- for (int i = 0; i < n; i++) {
- long long u = ((long long) floor(fc[i].x + 0.5)) % mod;
- long long v = ((long long) floor(fd[i].x + 0.5)) % mod;
- long long w = ((long long) floor(fd[i].y + 0.5)) % mod;
- c[i] = ((u << magic) + v + (w << magic + magic)) % mod;
- }
- }
- vector<int> multiply(vector<int> a, vector<int> b, int mod = (int) 1e9 + 7) {
- static int fa[maxf], fb[maxf], fc[maxf];
- int na = a.size(), nb = b.size();
- for (int i = 0; i < na; i++) fa[i] = a[i];
- for (int i = 0; i < nb; i++) fb[i] = b[i];
- multiply(fa, fb, na, nb, fc, mod, a == b);
- int k = na + nb - 1;
- vector<int> res(k);
- for (int i = 0; i < k; i++) res[i] = fc[i];
- return res;
- }
- int fpow(int a, int k, int p) {
- if (!k) return 1;
- int res = a, t = a; k--;
- while (k) {
- if (k & 1) res = (long long) res * t % p;
- t = (long long) t * t % p;
- k >>= 1;
- }
- return res;
- }
- vector<int> invert(vector<int> a, int n, int mod){
- assert(a[0] != 0);
- vector<int> x(1, fpow(a[0], mod - 2, mod));
- while (x.size() < n) {
- vector<int> tmp(a.begin(), a.begin() + min(a.size(), 2 * x.size()));
- vector<int> nx = multiply(multiply(x, x, mod), tmp, mod);
- x.resize(2 * x.size());
- for (int i = 0; i < x.size(); i++) {
- x[i] += x[i];
- x[i] -= nx[i];
- if (x[i] < 0) x[i] += mod;
- if (x[i] >= mod) x[i] -= mod;
- }
- }
- x.resize(n);
- return x;
- }
- pair<vector<int>, vector<int> > divmod(vector<int> a, vector<int> b, int mod) {
- int n = a.size(), m = b.size();
- if (n < m) {
- return make_pair(vector<int>(), a);
- }
- reverse(a.begin(), a.end());
- reverse(b.begin(), b.end());
- vector<int> rb = invert(b, n - m + 1, mod);
- vector<int> d = multiply(a, rb, mod);
- reverse(a.begin(), a.end());
- reverse(b.begin(), b.end());
- while (d.size() > n - m + 1) d.pop_back();
- reverse(d.begin(), d.end());
- vector<int> r = multiply(d, b, mod);
- while (r.size() >= m) r.pop_back();
- for (int i = 0; i < m; i++) {
- r[i] = a[i] - r[i];
- if (r[i] < 0) r[i] += mod;
- }
- return make_pair(d, r);
- }
- vector<int> chirpz_transform(vector<int> a, int z, int k, int mod) {
- int n = a.size();
- vector<int> x;
- vector<int> y;
- int iz = fpow(z, mod - 2, mod);
- for (int i = 0; i < n; i++) {
- x.push_back((long long) a[i] * fpow(z, (long long) i * i, mod) % mod);
- }
- for (int i = 1 - n; i < k; i++) {
- y.push_back(fpow(iz, (long long) i * i, mod));
- }
- vector<int> r = FFT::multiply(x, y, mod);
- vector<int> res(k);
- for (int i = 0; i < k; i++) {
- res[i] = (long long) r[i + n - 1] * fpow(z, (long long) i * i, mod) % mod;
- }
- return res;
- }
- }
- #undef double
- struct MFMC {
- //O(n ^ 2 * m ^ 2)
- struct Edge {
- int u, v;
- ll cap, cost;
- Edge() : u(), v(), cap(), cost() {}
- Edge(int _u, int _v, ll _cap, ll _cost) : u(_u), v(_v), cap(_cap), cost(_cost) {}
- };
- vector<Edge> ed;
- vector<vector<int>> g;
- vector<ll> dist;
- vector<bool> inq;
- vector<int> p;
- int n;
- int S, T;
- MFMC() : n(), S(), T() {}
- MFMC(int _n, int _S, int _T) {
- n = _n;
- S = _S;
- T = _T;
- g.resize(n + 3);
- dist.resize(n + 3);
- inq.resize(n + 3);
- p.resize(n + 3);
- ed = vector<Edge>();
- for(int i = 0; i < n; i++) g[i].clear();
- }
- void addEdge(int u, int v, ll cap, ll cost) {
- g[u].pb(ed.size());
- ed.pb(Edge(u, v, cap, cost));
- g[v].pb(ed.size());
- ed.pb(Edge(v, u, 0, -cost));
- }
- bool spfa() {
- for(int i = 0; i <= n; i++) {
- dist[i] = INF;
- inq[i] = false;
- p[i] = -1;
- }
- dist[S] = 0;
- queue<int> q;
- q.push(S); inq[S] = true;
- while(!q.empty()) {
- int u = q.front(); q.pop(); inq[u] = false;
- for(int i = 0; i < (int)g[u].size(); i++) {
- Edge e = ed[g[u][i]];
- if(!e.cap) continue;
- if(dist[e.v] > dist[u] + e.cost) {
- dist[e.v] = dist[u] + e.cost;
- p[e.v] = g[u][i];
- if(!inq[e.v]) {
- q.push(e.v);
- inq[e.v] = true;
- }
- }
- }
- }
- return (p[T] >= 0);
- }
- pll Flow() {
- //return (maxflow, cost)
- ll flow = 0, cost = 0;
- while(spfa()) {
- int u = T;
- ll f = INF;
- while(u != S) {
- f = min(f, ed[p[u]].cap);
- u = ed[p[u]].u;
- }
- flow += f; cost += f * dist[T];
- u = T;
- while(u != S) {
- ed[p[u]].cap -= f;
- ed[p[u] ^ 1].cap += f;
- u = ed[p[u]].u;
- }
- }
- return make_pair(flow, cost);
- }
- };
- struct Dinitz {
- struct Edges {
- int u, v;
- ll cap;
- Edges() : u(), v(), cap() {}
- Edges(int _u, int _v, ll _cap) : u(_u), v(_v), cap(_cap) {}
- };
- vector<vector<int>> g;
- vector<Edges> ed;
- vector<int> dist;
- vector<int> id;
- int S, T;
- int n;
- Dinitz() : ed(), n(), S(), T() {}
- Dinitz(int _n, int _S, int _T) {
- n = _n; S = _S; T = _T;
- g.resize(n);
- dist.resize(n);
- id.resize(n);
- for(int i = 0; i < n; i++) g[i].clear();
- ed = vector<Edges>();
- }
- void addEdge(int u, int v, ll cap) {
- g[u].pb((int)ed.size());
- ed.pb(Edges(u, v, cap));
- g[v].pb((int)ed.size());
- ed.pb(Edges(v, u, 0));
- }
- bool bfs() {
- for(int i = 0; i < n; i++) dist[i] = n + 5;
- queue<int> q;
- q.push(S); dist[S] = 0;
- while(!q.empty()) {
- int u = q.front(); q.pop();
- for(int i : g[u]) {
- Edges e = ed[i];
- if(!e.cap) continue;
- if(dist[e.v] <= dist[u] + 1) continue;
- dist[e.v] = dist[u] + 1;
- q.push(e.v);
- }
- }
- return dist[T] < n + 5;
- }
- ll dfs(int u, ll flow) {
- if(u == T || flow == 0) return flow;
- ll ans = 0;
- for(int &i = id[u]; i < (int)g[u].size(); i++) {
- Edges e = ed[g[u][i]];
- if(!e.cap) continue;
- if(dist[e.v] != dist[u] + 1) continue;
- ll f = dfs(e.v, min(flow, e.cap));
- flow -= f;
- ans += f;
- ed[g[u][i]].cap -= f;
- ed[g[u][i] ^ 1].cap += f;
- if(flow == 0) return ans;
- }
- return ans;
- }
- ll Flow() {
- ll ans = 0;
- while(bfs()) {
- for(int i = 0; i < n; i++) id[i] = 0;
- ans += dfs(S, INF * INF);
- }
- return ans;
- }
- };
- struct TWOSAT {
- int n;
- vector<vector<int>> g;
- vector<vector<int>> ed;
- vector<int> Num;
- vector<int> Low;
- vector<int> idComp;
- vector<bool> visited;
- stack<int> st;
- vector<int> ord;
- vector<int> idSort;
- int Time, cntComp;
- TWOSAT(int _n = 0) {
- n = _n;
- g.resize(2 * n + 2);
- ed.resize(2 * n + 2);
- Num.resize(2 * n + 2);
- Low.resize(2 * n + 2);
- visited.resize(2 * n + 2);
- idComp.resize(2 * n + 2);
- idSort.resize(2 * n + 2);
- ord.clear();
- Time = cntComp = 0;
- for(int i = 1; i <= 2 * n; i++) {
- g[i].clear(); ed[i].clear();
- idSort[i] = Num[i] = visited[i] = Low[i] = idComp[i] = 0;
- }
- }
- int NOT(int u) {
- return (u > n ? u - n : u + n);
- }
- void Connect(int u, int v) {
- g[u].pb(v);
- }
- void addEdge(int u, int v) {
- // u || v = 1
- Connect(NOT(u), v);
- Connect(NOT(v), u);
- }
- void tarjan(int u) {
- Num[u] = Low[u] = ++Time;
- st.push(u);
- for(auto v : g[u]) {
- if(Num[v]) {
- Low[u] = min(Low[u], Num[v]);
- } else {
- tarjan(v);
- Low[u] = min(Low[u], Low[v]);
- }
- }
- if(Num[u] == Low[u]) {
- int v = 0;
- ++cntComp;
- do {
- v = st.top(); st.pop();
- idComp[v] = cntComp;
- Num[v] = Low[v] = INF;
- } while(v != u);
- }
- }
- void topo(int u) {
- visited[u] = true;
- for(auto v : ed[u]) {
- if(!visited[v]) topo(v);
- }
- ord.pb(u);
- }
- vector<int> do2SAT() {
- for(int i = 1; i <= 2 * n; i++) {
- if(!Num[i]) tarjan(i);
- }
- for(int i = 1; i <= n; i++) {
- if(idComp[i] == idComp[i + n]) return {-1};
- }
- vector<int> ans;
- for(int i = 1; i <= 2 * n; i++) {
- int u = idComp[i];
- for(auto v : g[i]) {
- v = idComp[v];
- if(u == v) continue;
- ed[u].pb(v);
- }
- }
- for(int i = 1; i <= cntComp; i++) {
- if(!visited[i]) topo(i);
- }
- reverse(all(ord));
- for(int i = 0; i < cntComp; i++) idSort[ord[i]] = i + 1;
- for(int i = 1; i <= n; i++) {
- int u = idComp[i], v = idComp[i + n];
- if(idSort[u] > idSort[v]) ans.pb(i);
- }
- return ans;
- }
- };
- struct LiChaoTree {
- int n;
- struct Line {
- ll a = 0, b = INF * INF;
- Line(ll _a = 0, ll _b = 0) : a(_a), b(_b) {}
- };
- vector<Line> Node;
- LiChaoTree(int _n = 0) {
- n = _n;
- Node.resize(4 * n + 7);
- }
- private:
- ll f(Line u, ll x) {return u.a * x + u.b;}
- void AddLine(Line u, int L, int R, int id) {
- int mid = (L + R) >> 1;
- bool left = f(u, L) < f(Node[id], L);
- bool m = f(u, mid) < f(Node[id], mid);
- if(m) swap(u, Node[id]);
- if(L == R) return;
- if(m != left) AddLine(u, L, mid, id << 1);
- else AddLine(u, mid + 1, R, id << 1 | 1);
- }
- ll Get(int L, int R, int x, int id) {
- if(L > x || R < x) return INF * INF;
- int mid = (L + R) >> 1;
- ll ans = f(Node[id], x);
- if(L == R) return ans;
- if(x <= mid) minimize(ans, Get(L, mid, x, id << 1));
- else minimize(ans, Get(mid + 1, R, x, id << 1 | 1));
- return ans;
- }
- public:
- void addLine(ll a, ll b) {
- AddLine(Line(a, b), 1, n, 1);
- }
- ll get(int x) {
- return Get(1, n, x, 1);
- }
- };
- struct ConvexHullTrick {
- struct Line {
- ll a, b;
- Line(ll _a = 0, ll _b = -INF * INF) : a(_a), b(_b) {};
- };
- deque<pair<Line, int>> Convex;
- ll f(Line u, ll x) {return u.a * x + u.b;}
- ll find_inter(Line u, Line v) {
- return (v.b - u.b + u.a - v.a - 1) / (u.a - v.a);
- }
- void add(ll a, ll b) {
- Line u = Line(a, b);
- while(Convex.size()) {
- Line v = Convex.back().fi;
- ll x = find_inter(u, v);
- if(x <= Convex.back().se) {
- Convex.pop_back();
- } else {
- Convex.pb(mp(u, x));
- return;
- }
- }
- Convex.pb(mp(u, 0));
- }
- ll get(ll x) {
- while(Convex.size() > 1) {
- pair<Line, int> v = Convex.front();
- Convex.pop_front();
- if(x >= Convex.front().se) continue;
- else {
- Convex.pf(v);
- break;
- }
- }
- if(Convex.empty()) return -INF * INF;
- return f(Convex.front().fi, x);
- }
- };
- vector<int> z_function(string s) {
- int n = (int) s.length();
- vector<int> z(n);
- for (int i = 1, l = 0, r = 0; i < n; ++i) {
- if (i <= r)
- z[i] = min (r - i + 1, z[i - l]);
- while (i + z[i] < n && s[z[i]] == s[i + z[i]])
- ++z[i];
- if (i + z[i] - 1 > r)
- l = i, r = i + z[i] - 1;
- }
- return z;
- }
- #include <stdio.h>
- #include <string.h>
- #include <algorithm>
- #include <iostream>
- #include <string>
- using namespace std;
- bool maximize(int &a, int b) {
- if (a < b)
- a = b;
- else
- return false;
- return true;
- }
- void prepare(char a[], char b[]) {
- int cnt = 0;
- b[++cnt] = '#';
- for (int i = 1; a[i]; i++) {
- b[++cnt] = a[i];
- b[++cnt] = '#';
- }
- b[++cnt] = 0;
- b[0] = '^';
- }
- int manacher(char b[]) {
- int C = 1, R = 1, n = strlen(b + 1);
- int *P = new int[n + 2], r = 0;
- for (int i = 2; i < n; i++) {
- int i_mirror = 2 * C - i;
- P[i] = (R > i) ? min(R - i, P[i_mirror]) : 0;
- while (b[i - 1 - P[i]] == b[i + 1 + P[i]]) P[i]++;
- maximize(r, P[i]);
- if (i + P[i] > R) {
- C = i;
- R = i + P[i];
- }
- }
- delete[] P;
- return r;
- }
- using num = modnum<MOD>;
- string B = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
- int id[300];
- bool a[N];
- int cnt[10000][2];
- num pref[N][2], suff[N][2];
- int prv[N], nxt[N];
- int last[2];
- void BaoJiaoPisu() {
- int n; cin >> n;
- string s; cin >> s;
- for(int i = 0; i < 64; i++) id[B[i]] = i;
- int sz = 0;
- for(int i = 0; i < s.size(); i++) {
- int x = id[s[i]];
- for(int j = 0; j < 6; j++) {
- a[++sz] = (x >> j & 1);
- }
- }
- if(n <= 1e3) {
- for(int i = 1; i <= n; i++) {
- cnt[i][0] = cnt[i - 1][0] + (a[i] == 0);
- cnt[i][1] = cnt[i - 1][1] + (a[i] == 1);
- }
- ll ans = 0;
- for(int i = 1; i <= n; i++) {
- for(int j = i; j <= n; j++) {
- int x = cnt[j][1] - cnt[i - 1][1];
- int y = cnt[j][0] - cnt[i - 1][0];
- if(!x) ans += 1ll * y * y;
- else if(!y) ans += 1ll * x * x;
- else ans += 1ll * x * y;
- ans %= MOD;
- }
- }
- cout << ans;
- return;
- }
- for(int i = 1; i <= n; i++) {
- int x = a[i];
- prv[i] = last[x ^ 1];
- last[x] = i;
- }
- last[0] = last[1] = n + 1;
- for(int i = n; i >= 1; i--) {
- int x = a[i];
- nxt[i] = last[x ^ 1];
- last[x] = i;
- }
- for(int i = 1; i <= n; i++) {
- pref[i][0] = pref[i - 1][0];
- pref[i][1] = pref[i - 1][1];
- int x = a[i];
- pref[i][x] += i;
- }
- for(int i = n; i >= 1; i--) {
- suff[i][0] = suff[i + 1][0];
- suff[i][1] = suff[i + 1][1];
- int x = a[i];
- suff[i][x] += n - i + 1;
- }
- num ans = 0;
- num inv2 = num(1) / num(2);
- for(int i = 1; i <= n; i++) {
- num l = i - prv[i] - 1;
- num r = nxt[i] - i;
- ans += l * (l + 1) * inv2 * r;
- ans += r * (r + 1) * inv2 * (l + 1);
- int x = a[i];
- if(!x) continue;
- ans += pref[i][x ^ 1] * num(n - i + 1);
- ans += suff[i][x ^ 1] * num(i);
- }
- cout << ans;
- }
- int main()
- {
- ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
- #ifndef ONLINE_JUDGE
- freopen("input.txt", "r", stdin);
- freopen("output.txt", "w", stdout);
- #else
- //online
- freopen("DYSLEXIA.inp", "r", stdin);
- freopen("DYSLEXIA.out", "w", stdout);
- #endif
- int tc = 1, ddd = 0;
- // cin >> tc;
- while(tc--) {
- //ddd++;
- //cout << "Case #" << ddd << ": ";
- BaoJiaoPisu();
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement