From efe66b9949921de6185fb353ef7c3fa56d9eae0d Mon Sep 17 00:00:00 2001
From: Bruno Freitas Tissei <bft15@inf.ufpr.br>
Date: Sun, 3 Mar 2019 16:32:31 -0300
Subject: [PATCH] Finish SBC17 and add FFT

Signed-off-by: Bruno Freitas Tissei <bft15@inf.ufpr.br>
---
 algorithms/math/fast_matrix_pow.cpp |  50 +++++---
 algorithms/math/fft.cpp             | 130 +++++++++++++++++++++
 contests/Cadernaveis/URI1477.cpp    |   4 +-
 contests/SBC17/A.cpp                | 158 +++++++++++++++++++++++++
 contests/SBC17/B.cpp                |  56 +++++++++
 contests/SBC17/C.cpp                |  51 +++++++++
 contests/SBC17/H.cpp                |  51 +++++++++
 contests/SBC17/I.cpp                |  64 +++++++++++
 contests/SBC17/K.cpp                | 107 +++++++++++++++++
 contests/SBC17/L.cpp                | 171 ++++++++++++++++++++++++++++
 misc/template.cpp                   |   1 -
 11 files changed, 826 insertions(+), 17 deletions(-)
 create mode 100644 algorithms/math/fft.cpp
 create mode 100644 contests/SBC17/A.cpp
 create mode 100644 contests/SBC17/B.cpp
 create mode 100644 contests/SBC17/C.cpp
 create mode 100644 contests/SBC17/H.cpp
 create mode 100644 contests/SBC17/I.cpp
 create mode 100644 contests/SBC17/K.cpp
 create mode 100644 contests/SBC17/L.cpp

diff --git a/algorithms/math/fast_matrix_pow.cpp b/algorithms/math/fast_matrix_pow.cpp
index c8c02ef..7146188 100644
--- a/algorithms/math/fast_matrix_pow.cpp
+++ b/algorithms/math/fast_matrix_pow.cpp
@@ -20,36 +20,47 @@
 //   [x1  x2]^n
 //   [ 1   0]
 
+
 #define K 2
 
-struct mat {
+struct matrix {
   ll m[K][K];
 
   // Matrix multiplication - O(k^3)
-  mat operator*(mat a) {
-    mat aux;
+  matrix operator*(matrix a) {
+    matrix aux;
 
-    for(int i = 0; i < K; i++)
-      for(int j = 0; j < K; j++) {
+    for (int i = 0; i < K; i++)
+      for (int j = 0; j < K; j++) {
         ll sum = 0;
-        for(int k = 0; k < K; k++)
-          sum += (m[i][k] * a.m[k][j]) % MOD;
-        aux.m[i][j] = sum % MOD;
-      }
 
+        for (int k = 0; k < K; k++)
+          sum += (m[i][k] * a[k][j]) % MOD;
+
+        aux[i][j] = sum % MOD;
+      }
+    
     return aux;
   }
+
+  ll *operator[](int i) {
+    return m[i];
+  }
+
+  void clear() {
+    mset(m, 0);
+  }
 };
 
 
 // Fast exponentiation (can be used with integers as well) - O(log n)
-ll mat_pow(mat in, ll n) {
-  mat ans, b = in;
+matrix matrix_pow(matrix in, ll n) {
+  matrix ans, b = in;
 
   // Set ans as identity matrix
-  memset(ans.m, 0, sizeof ans.m);
+  ans.clear();
   for (int i = 0; i < K; ++i)
-    ans.m[i][i] = 1;
+    ans[i][i] = 1;
 
   while (n) {
     if (n & 1)
@@ -61,3 +72,16 @@ ll mat_pow(mat in, ll n) {
 
   return ans;
 }
+
+
+// Solves f(n) = x * f(n - 1) + y * f(n - 2)
+matrix solve(ll x, ll y, ll n) {
+  matrix in;
+
+  in[0][0] = x % MOD;
+  in[0][1] = y % MOD;
+  in[1][0] = 1;
+  in[1][1] = 0;
+
+  return matrix_pow(in, n);
+}
diff --git a/algorithms/math/fft.cpp b/algorithms/math/fft.cpp
new file mode 100644
index 0000000..1e8a541
--- /dev/null
+++ b/algorithms/math/fft.cpp
@@ -0,0 +1,130 @@
+/**
+ * Fast Fourier Transform (FFT)
+ *
+ * Complexity (Time): O(N log N)
+ * Complexity (Space): O(N)
+ */
+
+struct comp {
+  float r, i;
+
+  comp() : r(0), i(0) {}
+  comp(float r, float i) : r(r), i(i) {}
+
+  comp operator+(comp b) { 
+    return comp(r + b.r, i + b.i); 
+  }
+
+  comp operator-(comp b) {
+    return comp(r - b.r, i - b.i);
+  }
+
+  comp operator*(comp b) {
+    return comp(r * b.r - i * b.i, r * b.i + i * b.r);
+  }
+
+  comp operator/(comp b) {
+    float div = (b.r * b.r) + (b.i * b.i);
+    return comp((r * b.r + i * b.i) / div, (i * b.r - r * b.i) / div);
+  }
+};
+
+
+// Returns complex conjugate
+inline comp conj(comp a) {
+  return comp(a.r, -a.i);
+}
+
+vector<int> rev = {0, 1};
+vector<comp> roots = {{0, 0}, {1, 0}};
+
+
+// Initializes reversed-bit vector (rev) and roots of unity vector (roots)
+void init(int nbase) {
+  rev.resize(1 << nbase);
+  roots.resize(1 << nbase);
+
+  // Construct rev vector
+  for (int i = 0; i < (1 << nbase); ++i)
+    rev[i] = (rev[i >> 1] >> 1) + ((i & 1) << (nbase - 1));
+
+  // Construct roots vector
+  for (int base = 1; base < nbase; ++base) {
+    float angle = 2 * M_PI / (1 << (base + 1));
+
+    for (int i = 1 << (base - 1); i < (1 << base); ++i) {
+      float angle_i = angle * (2 * i + 1 - (1 << base));
+
+      roots[i << 1] = roots[i];
+      roots[(i << 1) + 1] = comp(cos(angle_i), sin(angle_i));
+    }
+  }
+}
+
+
+// Applies FFT on vector a
+void fft(vector<comp> &a) {
+  int n = a.size();
+
+  // Change order of elements to match the end of recursion
+  for (int i = 0; i < n; ++i)
+    if (i < rev[i])
+      swap(a[i], a[rev[i]]);
+
+  // Iterate through "recursion tree"
+  for (int s = 1; s < n; s <<= 1) {
+
+    // Iterate through all pairs of vectors (tree leaves)
+    for (int k = 0; k < n; k += (s << 1)) {
+
+      // Execute "combine step"
+      for (int j = 0; j < s; ++j) {
+        comp z = a[k + j + s] * roots[j + s];
+
+        a[k + j + s] = a[k + j] - z;
+        a[k + j] = a[k + j] + z;
+      }
+    }
+  }
+}
+
+
+// Multiplies vectors a and b using FFT
+vector<int> multiply(vector<int> &a, vector<int> &b) {
+  int nbase, need = a.size() + b.size() + 1;
+
+  for (nbase = 0; (1 << nbase) < need; ++nbase);
+  init(nbase);
+
+  int size = 1 << nbase;
+  vector<comp> fa(size);
+
+  // Assemble vector fa from a and b
+  for (int i = 0; i < size; ++i) {
+    int x = (i < a.size() ? a[i] : 0);
+    int y = (i < b.size() ? b[i] : 0);
+    fa[i] = comp(x, y);
+  }
+
+  fft(fa);
+
+  // Multiply vectors using magic
+  comp r(0, -0.25 / size);
+  for (int i = 0; i <= (size >> 1); ++i) {
+    int j = (size - i) & (size - 1);
+    comp z = (fa[j] * fa[j] - conj(fa[i] * fa[i])) * r;
+
+    if (i != j)
+      fa[j] = (fa[i] * fa[i] - conj(fa[j] * fa[j])) * r;
+    fa[i] = z;
+  }
+
+  fft(fa);
+
+  // Obtain result vector
+  vector<int> res(need);
+  for (int i = 0; i < need; ++i)
+    res[i] = fa[i].r + 0.5;
+
+  return res;
+}
diff --git a/contests/Cadernaveis/URI1477.cpp b/contests/Cadernaveis/URI1477.cpp
index 289d7ed..c8b0c0c 100644
--- a/contests/Cadernaveis/URI1477.cpp
+++ b/contests/Cadernaveis/URI1477.cpp
@@ -71,7 +71,6 @@ void build(int node = 1, int a = 0, int b = N - 1) {
 
 void push(int node, int a, int b, int val) {
   tree[node].change(val);
-  // tree[node] += (b - a + 1) * val; (for Range Sum Query)
 
   if (a != b) {
     lazy[left(node)] += val;
@@ -141,9 +140,8 @@ int main() {
       if (op == 'C') {
         elem x = query(a - 1, b - 1);
         cout << x.h << " " << x.e << " " << x.r << ende;
-      } else {
+      } else
         update(a - 1, b - 1);
-      }
     }
 
     cout << ende;
diff --git a/contests/SBC17/A.cpp b/contests/SBC17/A.cpp
new file mode 100644
index 0000000..e39e7b0
--- /dev/null
+++ b/contests/SBC17/A.cpp
@@ -0,0 +1,158 @@
+#include <bits/stdc++.h>
+
+#define MAX 101010
+#define EPS 1e-6
+#define MOD 1000000007
+#define inf 0x3f3f3f3f
+#define llinf 0x3f3f3f3f3f3f3f3f
+
+#define fi first
+#define se second
+#define sz size()
+#define pb push_back
+#define ende '\n'
+
+#define all(x) (x).begin(), (x).end()
+#define rall(x) (x).rbegin(), (x).rend()
+#define mset(x, y) memset(&x, (y), sizeof(x))
+
+using namespace std; 
+
+typedef long long ll;
+typedef pair<int,int> ii;
+
+typedef struct elem {
+  int freq[9];
+
+  elem() {
+    for (int i = 0; i < 9; ++i) freq[i] = 0;
+  }
+
+  elem(int x) {
+    for (int i = 0; i < 9; ++i) freq[i] = 0;
+    freq[x] = 1;
+  }
+
+  elem operator+(const elem &a) {
+    elem e;
+    for (int i = 0; i < 9; ++i)
+      e.freq[i] = a.freq[i] + freq[i];
+    return e;
+  }
+
+  void change(int x) {
+    vector<int> aux(9, 0);
+    for (int i = 0; i < 9; ++i)
+      aux[(i + x) % 9] += freq[i];
+
+    for (int i = 0; i < 9; ++i)
+      freq[i] = aux[i];
+  }
+} elem;
+
+
+int N;
+elem v[MAX];
+elem tree[4 * MAX];
+int lazy[4 * MAX];
+
+#define left(x) (x << 1)
+#define right(x) ((x << 1) + 1)
+
+void build(int node = 1, int a = 0, int b = N - 1) {
+  if (a > b) 
+    return;
+
+  if (a == b) {
+    tree[node] = v[a];
+    return;
+  }
+
+  build(left(node), a, (a + b) / 2);
+  build(right(node), (a + b) / 2 + 1, b);
+  tree[node] = tree[node * 2] + tree[node * 2 + 1];
+}
+
+
+void push(int node, int a, int b, int val) {
+  tree[node].change(val);
+
+  if (a != b) {
+    lazy[left(node)] += val;
+    lazy[right(node)] += val;
+  }
+
+  lazy[node] = 0;
+}
+
+
+void update(int i, int j, int val, int node = 1, int a = 0, int b = N - 1) {
+  if (lazy[node] != 0)
+    push(node, a, b, lazy[node]);
+
+  if (a > b || a > j || b < i) 
+    return;
+
+  if (i <= a && b <= j) {
+    push(node, a, b, val);
+    return;
+  }
+
+  update(i, j, val, left(node), a, (a + b) / 2);
+  update(i, j, val, right(node), (a + b) / 2 + 1, b);
+  tree[node] = tree[node * 2] + tree[node * 2 + 1];
+}
+
+
+elem query(int i, int j, int node = 1, int a = 0, int b = N - 1) {
+  if (a > b || a > j || b < i)
+    return elem();
+
+  if (lazy[node])
+    push(node, a, b, lazy[node]);
+
+  if (a >= i && b <= j)
+    return tree[node];
+
+  elem q1 = query(i, j, left(node), a, (a + b) / 2);
+  elem q2 = query(i, j, right(node), (a + b) / 2 + 1, b);
+  return q1 + q2;
+}
+
+
+int main() {
+  ios::sync_with_stdio(0);
+  cin.tie(0);
+
+  int n, q; cin >> n >> q;
+  for (int i = 0; i < n; ++i)
+    v[i] = elem(1);
+
+  N = n;
+  build();
+
+  for (int i = 0; i < q; ++i) {
+    int a, b; cin >> a >> b;
+    elem e = query(a, b);
+
+    int grt = 0;
+    for (int i = 1; i < 9; ++i)
+      if (e.freq[i] >= e.freq[grt])
+        grt = i;
+
+    update(a, b, grt);
+  }
+
+  for (int i = 0; i < n; ++i) {
+    elem e = query(i, i);
+
+    int grt = 0;
+    for (int i = 0; i < 9; ++i)
+      if (e.freq[i] >= e.freq[grt])
+        grt = i;
+
+    cout << grt << ende;
+  }
+
+  return 0;
+}
diff --git a/contests/SBC17/B.cpp b/contests/SBC17/B.cpp
new file mode 100644
index 0000000..38a2619
--- /dev/null
+++ b/contests/SBC17/B.cpp
@@ -0,0 +1,56 @@
+#include <bits/stdc++.h>
+
+#define EPS 1e-6
+#define MOD 1000000007
+#define inf 0x3f3f3f3f
+#define llinf 0x3f3f3f3f3f3f3f3f
+
+#define fi first
+#define se second
+#define sz size()
+#define pb push_back
+#define ende '\n'
+
+#define all(x) (x).begin(), (x).end()
+#define rall(x) (x).rbegin(), (x).rend()
+#define mset(x, y) memset(&x, (y), sizeof(x))
+
+using namespace std; 
+
+typedef long long ll;
+typedef pair<int,int> ii;
+
+
+int main() {
+  ios::sync_with_stdio(0);
+  cin.tie(0);
+
+  ll n, t, a0, x, y;
+  cin >> n >> t >> a0 >> x >> y;
+
+  vector<ll> tor(t);
+  for (auto &i : tor) cin >> i;
+
+  auto next = [&]() {
+    ll xxor = 0;
+    for (auto i : tor)
+      xxor ^= !!(a0 & (1 << i));
+    return a0 = ((a0 >> 1) | (xxor << (n - 1)));
+  };
+
+
+  vector<ll> idx(x + 1, 0);
+  idx[0] = 1;
+
+  ll acc = a0 % x;
+  for (ll i = 2; ; ++i) {
+    if (idx[acc] && i - idx[acc] >= y)
+      return cout << idx[acc] - 1 << " " << i - 2 << ende, 0;
+    else if (!idx[acc])
+      idx[acc] = i;
+
+    acc = (acc + next()) % x;
+  }
+
+  return 0;
+}
diff --git a/contests/SBC17/C.cpp b/contests/SBC17/C.cpp
new file mode 100644
index 0000000..059e9d5
--- /dev/null
+++ b/contests/SBC17/C.cpp
@@ -0,0 +1,51 @@
+#include <bits/stdc++.h>
+
+#define EPS 1e-6
+#define MOD 1000000007
+#define inf 0x3f3f3f3f
+#define llinf 0x3f3f3f3f3f3f3f3f
+
+#define fi first
+#define se second
+#define sz size()
+#define pb push_back
+#define ende '\n'
+
+#define all(x) (x).begin(), (x).end()
+#define rall(x) (x).rbegin(), (x).rend()
+#define mset(x, y) memset(&x, (y), sizeof(x))
+
+using namespace std; 
+
+typedef long long ll;
+typedef pair<int,int> ii;
+
+ll lcm(ll a, ll b) {
+  return (a * b) / __gcd(a, b);
+}
+
+
+int main() {
+  ios::sync_with_stdio(0);
+  cin.tie(0);
+
+  ll n, l; cin >> n >> l;
+  ll acc = 1;
+  for (int i = 0; i < n; ++i) {
+    ll x; cin >> x;
+    acc = lcm(acc, x);
+  }
+
+  ll ans = -1;
+  ll grt = -1;
+  for (int i = 1; i <= l; ++i) {
+    ll lc = lcm(acc, i);
+    if (lc > grt && lc <= l) {
+      grt = lc; 
+      ans = i;
+    }
+  }
+
+  cout << ans << ende;
+  return 0;
+}
diff --git a/contests/SBC17/H.cpp b/contests/SBC17/H.cpp
new file mode 100644
index 0000000..9a9b265
--- /dev/null
+++ b/contests/SBC17/H.cpp
@@ -0,0 +1,51 @@
+#include <bits/stdc++.h>
+
+#define MAX 200
+#define EPS 1e-6
+#define MOD 1000000007
+#define inf 0x3f3f3f3f
+#define llinf 0x3f3f3f3f3f3f3f3f
+
+#define fi first
+#define se second
+#define sz size()
+#define pb push_back
+#define ende '\n'
+
+#define all(x) (x).begin(), (x).end()
+#define rall(x) (x).rbegin(), (x).rend()
+#define mset(x, y) memset(&x, (y), sizeof(x))
+
+using namespace std; 
+
+typedef long long ll;
+typedef pair<int,int> ii;
+typedef pair<double,double> dd;
+
+int dp[MAX][MAX];
+
+int main() {
+  ios::sync_with_stdio(0);
+  cin.tie(0);
+
+  int n; cin >> n;
+  double xa, xb; cin >> xa >> xb;
+
+  vector<dd> pp;
+  pp.pb(dd(-1, -1));
+  for (int i = 0; i < n; ++i) {
+    double x, y; cin >> x >> y; 
+    pp.pb(dd(asin(y / hypot(xa - x, y)), asin(y / hypot(xb - x, y))));
+  }
+
+  sort(all(pp));
+  for (int i = n + 1; i >= 1; --i)
+    for (int j = 0; j <= n; ++j)
+      if (j == 0 || (pp[i].fi > pp[j].fi && pp[i].se > pp[j].se))
+        dp[i][j] = max(dp[i+1][i] + 1, dp[i+1][j]);
+      else
+        dp[i][j] = dp[i+1][j];
+
+  cout << dp[1][0] << ende;
+  return 0;
+}
diff --git a/contests/SBC17/I.cpp b/contests/SBC17/I.cpp
new file mode 100644
index 0000000..a784084
--- /dev/null
+++ b/contests/SBC17/I.cpp
@@ -0,0 +1,64 @@
+#include <bits/stdc++.h>
+
+#define MAX 10101
+#define EPS 1e-6
+#define MOD 1000000007
+#define inf 0x3f3f3f3f
+#define llinf 0x3f3f3f3f3f3f3f3f
+
+#define fi first
+#define se second
+#define sz size()
+#define pb push_back
+#define ende '\n'
+
+#define all(x) (x).begin(), (x).end()
+#define rall(x) (x).rbegin(), (x).rend()
+#define mset(x, y) memset(&x, (y), sizeof(x))
+
+using namespace std; 
+
+typedef long long ll;
+typedef pair<int,int> ii;
+
+int C;
+int ans = 0;
+int E[MAX];
+bool cont[MAX];
+vector<ii> graph[MAX];
+
+int dfs(int x) {
+  cont[x] = true;
+
+  for (auto i : graph[x]) {
+    if (!cont[i.fi]) {
+      E[x] += dfs(i.fi);
+      ans += 2 * i.se * ((E[i.fi] - 1) / C + 1);
+    }
+  }
+
+  return E[x];
+}
+
+
+int main() {
+  ios::sync_with_stdio(0);
+  cin.tie(0);
+
+  int n; cin >> n >> C;
+  for (int i = 0; i < n; ++i)
+    cin >> E[i];
+
+  for (int i = 0; i < n - 1; ++i) {
+    int a, b, c; cin >> a >> b >> c;
+    a--, b--;
+    graph[a].pb(ii(b, c));
+    graph[b].pb(ii(a, c));
+  }
+
+
+  dfs(0);
+  cout << ans << ende;
+
+  return 0;
+}
diff --git a/contests/SBC17/K.cpp b/contests/SBC17/K.cpp
new file mode 100644
index 0000000..cbc6648
--- /dev/null
+++ b/contests/SBC17/K.cpp
@@ -0,0 +1,107 @@
+#include <bits/stdc++.h>
+
+#define EPS 1e-6
+#define MOD 10000
+#define inf 0x3f3f3f3f
+#define llinf 0x3f3f3f3f3f3f3f3f
+
+#define fi first
+#define se second
+#define sz size()
+#define pb push_back
+#define ende '\n'
+
+#define all(x) (x).begin(), (x).end()
+#define rall(x) (x).rbegin(), (x).rend()
+#define mset(x, y) memset(&x, (y), sizeof(x))
+
+using namespace std; 
+
+typedef long long ll;
+typedef pair<int,int> ii;
+
+#define K 2
+
+template <typename T>
+struct matrix {
+  T m[K][K];
+
+  // Matrix multiplication - O(k^3)
+  matrix operator*(matrix a) {
+    matrix aux;
+
+    for (int i = 0; i < K; i++)
+      for (int j = 0; j < K; j++) {
+        ll sum = 0;
+
+        for (int k = 0; k < K; k++)
+          sum += (m[i][k] * a[k][j]) % MOD;
+
+        aux[i][j] = sum % MOD;
+      }
+    
+    return aux;
+  }
+
+  T *operator[](int i) {
+    return m[i];
+  }
+
+  void clear() {
+    mset(m, 0);
+  }
+};
+
+
+// Fast exponentiation (can be used with integers as well) - O(log n)
+matrix<ll> matrix_pow(matrix<ll> in, ll n) {
+  matrix<ll> ans, b = in;
+
+  // Set ans as identity matrix
+  ans.clear();
+  for (int i = 0; i < K; ++i)
+    ans[i][i] = 1;
+
+  while (n) {
+    if (n & 1)
+      ans = ans * b;
+
+    n >>= 1;
+    b = b * b;
+  }
+
+  return ans;
+}
+
+
+// Solves f(n) = x * f(n - 1) + y * f(n - 2)
+matrix<ll> solve(ll x, ll y, ll n) {
+  matrix<ll> in;
+
+  in[0][0] = x % MOD;
+  in[0][1] = y % MOD;
+  in[1][0] = 1;
+  in[1][1] = 0;
+
+  return matrix_pow(in, n);
+}
+
+
+int main() {
+  ios::sync_with_stdio(0);
+  cin.tie(0);
+
+  ll a, b, n, k; cin >> a >> b >> n >> k;
+
+  matrix<ll> ans = solve(2 * a, (b - a * a) + MOD, n - 1);
+  ll res = (ans[0][0] * 2 * a + ans[0][1] * 2) % MOD;
+
+  if (a * a > b || (a * a < b && n % 2 == 0))
+    res = ((res - 1) + MOD) % MOD;
+
+  for (int i = 0; i < k-1; ++i)
+    res /= 10;
+  
+  cout << res % 10 << ende;
+  return 0;
+}
diff --git a/contests/SBC17/L.cpp b/contests/SBC17/L.cpp
new file mode 100644
index 0000000..ae20c47
--- /dev/null
+++ b/contests/SBC17/L.cpp
@@ -0,0 +1,171 @@
+#include <bits/stdc++.h>
+
+#define EPS 1e-6
+#define MOD 1000000007
+#define inf 0x3f3f3f3f
+#define llinf 0x3f3f3f3f3f3f3f3f
+
+#define fi first
+#define se second
+#define pb push_back
+#define ende '\n'
+
+#define all(x) (x).begin(), (x).end()
+#define rall(x) (x).rbegin(), (x).rend()
+#define mset(x, y) memset(&x, (y), sizeof(x))
+
+using namespace std; 
+
+typedef long long ll;
+typedef pair<int,int> ii;
+
+struct comp {
+  float r, i;
+
+  comp() : r(0), i(0) {}
+  comp(float r, float i) : r(r), i(i) {}
+
+  comp operator+(comp b) { 
+    return comp(r + b.r, i + b.i); 
+  }
+
+  comp operator-(comp b) {
+    return comp(r - b.r, i - b.i);
+  }
+
+  comp operator*(comp b) {
+    return comp(r * b.r - i * b.i, r * b.i + i * b.r);
+  }
+
+  comp operator/(comp b) {
+    float div = (b.r * b.r) + (b.i * b.i);
+    return comp((r * b.r + i * b.i) / div, (i * b.r - r * b.i) / div);
+  }
+};
+
+
+// Returns complex conjugate
+inline comp conj(comp a) {
+  return comp(a.r, -a.i);
+}
+
+vector<int> rev = {0, 1};
+vector<comp> roots = {{0, 0}, {1, 0}};
+
+
+// Initializes reversed-bit vector (rev) and roots of unity vector (roots)
+void init(int nbase) {
+  rev.resize(1 << nbase);
+  roots.resize(1 << nbase);
+
+  // Construct rev vector
+  for (int i = 0; i < (1 << nbase); ++i)
+    rev[i] = (rev[i >> 1] >> 1) + ((i & 1) << (nbase - 1));
+
+  // Construct roots vector
+  for (int base = 1; base < nbase; ++base) {
+    float angle = 2 * M_PI / (1 << (base + 1));
+
+    for (int i = 1 << (base - 1); i < (1 << base); ++i) {
+      float angle_i = angle * (2 * i + 1 - (1 << base));
+
+      roots[i << 1] = roots[i];
+      roots[(i << 1) + 1] = comp(cos(angle_i), sin(angle_i));
+    }
+  }
+}
+
+
+// Applies FFT on vector a
+void fft(vector<comp> &a) {
+  int n = a.size();
+
+  // Change order of elements to match the end of recursion
+  for (int i = 0; i < n; ++i)
+    if (i < rev[i])
+      swap(a[i], a[rev[i]]);
+
+  // Iterate through "recursion tree"
+  for (int s = 1; s < n; s <<= 1) {
+
+    // Iterate through all pairs of vectors (tree leaves)
+    for (int k = 0; k < n; k += (s << 1)) {
+
+      // Execute "combine step"
+      for (int j = 0; j < s; ++j) {
+        comp z = a[k + j + s] * roots[j + s];
+
+        a[k + j + s] = a[k + j] - z;
+        a[k + j] = a[k + j] + z;
+      }
+    }
+  }
+}
+
+
+// Multiplies vectors a and b using FFT
+vector<int> multiply(vector<int> &a, vector<int> &b) {
+  int nbase, need = a.size() + b.size() + 1;
+
+  for (nbase = 0; (1 << nbase) < need; ++nbase);
+  init(nbase);
+
+  int size = 1 << nbase;
+  vector<comp> fa(size);
+
+  // Assemble vector fa from a and b
+  for (int i = 0; i < size; ++i) {
+    int x = (i < a.size() ? a[i] : 0);
+    int y = (i < b.size() ? b[i] : 0);
+    fa[i] = comp(x, y);
+  }
+
+  fft(fa);
+
+  // Multiply vectors using magic
+  comp r(0, -0.25 / size);
+  for (int i = 0; i <= (size >> 1); ++i) {
+    int j = (size - i) & (size - 1);
+    comp z = (fa[j] * fa[j] - conj(fa[i] * fa[i])) * r;
+
+    if (i != j)
+      fa[j] = (fa[i] * fa[i] - conj(fa[j] * fa[j])) * r;
+    fa[i] = z;
+  }
+
+  fft(fa);
+
+  // Obtain result vector
+  vector<int> res(need);
+  for (int i = 0; i < need; ++i)
+    res[i] = fa[i].r + 0.5;
+
+  return res;
+}
+
+int main() {
+  ios::sync_with_stdio(0);
+  cin.tie(0);
+
+  string s; cin >> s;
+  int n = s.size();
+
+  int acc = 0, sum = s[0] - 'a' + 1;
+  for (int i = 1; i < n; ++i)
+    sum += s[i] - 'a' + 1;
+
+  vector<int> a(sum + 1), b(sum + 1);
+  a[0] = b[sum] = 1;
+  for (int i = 0; i < n; ++i) {
+    acc += s[i] - 'a' + 1;
+    a[acc] = b[sum - acc] = 1;
+  }
+
+  vector<int> c = multiply(a, b);
+  int ans = 0;
+  for (int i = sum + 1; i <= 2 * sum; ++i)
+    if (c[i]) ans++;
+
+  cout << ans << ende;
+  return 0;
+}
diff --git a/misc/template.cpp b/misc/template.cpp
index 70e0abe..c30f33f 100644
--- a/misc/template.cpp
+++ b/misc/template.cpp
@@ -7,7 +7,6 @@
 
 #define fi first
 #define se second
-#define sz size()
 #define pb push_back
 #define ende '\n'
 
-- 
GitLab