Problem p02983 (C++)

Buggy submission (status: Time Limit Exceeded):
// author: zekigurbuz
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef vector<bool> vb;
typedef vector<int> vi;
typedef vector<string> vs;
typedef vector<double> vd;
typedef vector<pii> vpii;
typedef queue<int> qi;
typedef map<string, int> msi;
#define RANGE_SUM 0
#define RANGE_MIN 1
#define RANGE_MAX 2
#define RANGE_XOR 3
#define RANGE_MUL 4
#define RANGE_OR 5
#define RANGE_AND 6
#define bit_ison(S, j) (S & (1 << j))
#define bit_setbit(S, j) (S |= (1 << j))
#define bit_clearbit(S, j) (S &= ~(1 << j))
#define bit_togglebit(S, j) (S ^= (1 << j))
#define bit_lowestbit(S) (S & (-S))
#define bit_setallon(S, n) (S = (1 << n) - 1)
#define bit_ispowertwo(S) (!(S & (S - 1))
#define bit_turnofflastbit(S) ((S) & (S - 1))
#define bit_turnonlastzero(S) ((S) | (S + 1))
#define int ll
#define double ld
#define M0D 1000000007
#define imin -(1e18)
#define imax 1e18
#define endl '\n'
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define forn(a, b) for (int a = 0; a < b; ++a)
#define rep(a, b, c) for (int a = b; a < c; ++a)
const ld PI = 4 * atan((ld)1);
vs split(string s) {
  vs v;
  istringstream iss(s);
  do {
    string sub;
    iss >> sub;
    v.pb(sub);
  } while (iss);
  v.pop_back();
  return v;
}
int gcd(int a, int b) { return a == 0 ? b : gcd(b % a, a); }
int lcm(int a, int b) { return a * b / gcd(a, b); }
int p0wm(int n, int p, int m) {
  if (p == 0)
    return 1;
  if (p == 1)
    return n % m;
  if (p % 2 == 0) {
    int t = p0wm(n, p / 2, m);
    return t % m * t % m % m;
  }
  int t = p0wm(n, p / 2, m);
  t = t % m * t % m % m;
  return t % m * n % m % m;
}
int p0w(int n, int p) {
  if (p == 0)
    return 1;
  if (p == 1)
    return n;
  if (p % 2 == 0) {
    int t = p0w(n, p / 2);
    return t * t;
  }
  int t = p0w(n, p / 2);
  return t * t * n;
}
int m0d(int n, int m) { return (m + (n % m)) % m; }
int fact(int n) {
  int a = 1;
  for (int i = 1; i <= n; ++i)
    a *= i;
  return a;
}
bool ip(int n) {
  if (n <= 1)
    return false;
  if (n == 2)
    return true;
  for (int i = 2; i * i <= n; ++i)
    if (n % i == 0)
      return false;
  return true;
}
vb ps(int n) {
  vector<bool> p;
  forn(i, n + 1) { p.pb(true); }
  p[0] = false;
  p[0] = p[1] = false;
  for (int i = 2; i * i <= n; ++i) {
    if (p[i]) {
      for (int j = i * i; j <= n; j += i) {
        p[j] = false;
      }
    }
  }
  return p;
}
vi psp(int n) {
  vector<bool> p = ps(n);
  vi a;
  forn(i, n + 1) if (p[i]) a.pb(i);
  return a;
}
// variables: vi pset, vi size, int numsets. methods: constructor(int n), int
// find_set(int i) void unify(int i, int j) bool same_set(int i, int j)
struct dsu {
  vi pset;
  vi size;
  int numsets;
  dsu(int n) {
    numsets = n;
    pset.resize(n);
    size.resize(n);
    forn(i, n) pset[i] = i;
    forn(i, n) size[i] = 1;
  }
  int find_set(int i) { return pset[i] == i ? i : pset[i] = find_set(pset[i]); }
  void unify(int i, int j) {
    int a = find_set(i), b = find_set(j);
    if (a == b)
      return;
    numsets--;
    if (size[a] < size[b]) {
      pset[a] = b;
      size[b] += size[a];
    } else {
      pset[b] = a;
      size[a] += size[b];
    }
  }
  bool same_set(int i, int j) { return find_set(i) == find_set(j); }
  int size_set(int i) { return size[find_set(i)]; }
};
// variables: vi bit, int size. methods: constructor(int n), int sum(int a), int
// sum(int a, int b), void update(int k, int x)
struct fenwick {
  vi bit;
  int size;
  fenwick(int n) {
    size = n;
    bit.resize(n + 1, 0);
  }
  int sum(int a) {
    int s = 0;
    while (a >= 1) {
      s += bit[a];
      a -= a & -a;
    }
    return s;
  }
  int sum(int a, int b) { return sum(b) - (a == 1 ? 0 : sum(a - 1)); }
  void update(int k, int x) {
    while (k <= size) {
      bit[k] += x;
      k += k & -k;
    }
  }
};
// variables: int code, int size, vi segment_tree. methods: constructor(int n,
// int type), void update(...), int query(...)
struct segtree {
  int code;
  int size;
  vi segment_tree;
  segtree(int n, int type) {
    n = (int)(2 * pow(2, floor(log2(n)) + 3));
    size = n;
    code = type;
    segment_tree.resize(n, 0);
  }
  void update(int index, int value) { update(1, 0, size - 1, index, value); }
  void update(int index, int left, int right, int i, int value) {
    if (left == right)
      segment_tree[index] = value;
    else {
      int mid = (left + right) / 2;
      if (i <= mid) {
        update(2 * index, left, mid, i, value);
      } else {
        update(2 * index + 1, mid + 1, right, i, value);
      }
      switch (code) {
      case RANGE_SUM:
        segment_tree[index] =
            segment_tree[2 * index] + segment_tree[2 * index + 1];
        break;
      case RANGE_MIN:
        segment_tree[index] =
            min(segment_tree[2 * index], segment_tree[2 * index + 1]);
        break;
      case RANGE_MAX:
        segment_tree[index] =
            max(segment_tree[2 * index], segment_tree[2 * index + 1]);
        break;
      case RANGE_XOR:
        segment_tree[index] =
            segment_tree[2 * index] ^ segment_tree[2 * index + 1];
        break;
      case RANGE_MUL:
        segment_tree[index] =
            segment_tree[2 * index] * segment_tree[2 * index + 1];
        break;
      case RANGE_OR:
        segment_tree[index] =
            segment_tree[2 * index] | segment_tree[2 * index + 1];
        break;
      case RANGE_AND:
        segment_tree[index] =
            segment_tree[2 * index] & segment_tree[2 * index + 1];
        break;
      }
    }
  }
  int query(int left, int right) { return query(1, 0, size - 1, left, right); }
  int query(int index, int left, int right, int lhs, int rhs) {
    if (left >= lhs && right <= rhs) {
      return segment_tree[index];
    } else {
      int ret = 0;
      switch (code) {
      case RANGE_SUM:
        ret = 0;
        break;
      case RANGE_MIN:
        ret = imax;
        break;
      case RANGE_MAX:
        ret = imin;
        break;
      case RANGE_XOR:
        ret = 0;
        break;
      case RANGE_MUL:
        ret = 1;
        break;
      case RANGE_OR:
        ret = 0;
        break;
      case RANGE_AND:
        ret = 9223372036854775807;
        break;
      }
      int mid = (left + right) / 2;
      if (mid >= lhs) {
        switch (code) {
        case RANGE_SUM:
          ret += query(2 * index, left, mid, lhs, rhs);
          break;
        case RANGE_MIN:
          ret = min(ret, query(2 * index, left, mid, lhs, rhs));
          break;
        case RANGE_MAX:
          ret = max(ret, query(2 * index, left, mid, lhs, rhs));
          break;
        case RANGE_XOR:
          ret ^= query(2 * index, left, mid, lhs, rhs);
          break;
        case RANGE_MUL:
          ret *= query(2 * index, left, mid, lhs, rhs);
          break;
        case RANGE_OR:
          ret |= query(2 * index, left, mid, lhs, rhs);
          break;
        case RANGE_AND:
          ret &= query(2 * index, left, mid, lhs, rhs);
          break;
        }
      }
      if (mid + 1 <= rhs) {
        switch (code) {
        case RANGE_SUM:
          ret += query(2 * index + 1, mid + 1, right, lhs, rhs);
          break;
        case RANGE_MIN:
          ret = min(ret, query(2 * index + 1, mid + 1, right, lhs, rhs));
          break;
        case RANGE_MAX:
          ret = max(ret, query(2 * index + 1, mid + 1, right, lhs, rhs));
          break;
        case RANGE_XOR:
          ret ^= query(2 * index + 1, mid + 1, right, lhs, rhs);
          break;
        case RANGE_MUL:
          ret *= query(2 * index + 1, mid + 1, right, lhs, rhs);
          break;
        case RANGE_OR:
          ret |= query(2 * index + 1, mid + 1, right, lhs, rhs);
          break;
        case RANGE_AND:
          ret &= query(2 * index + 1, mid + 1, right, lhs, rhs);
          break;
        }
      }
      return ret;
    }
  }
};

signed main() {
  ios_base::sync_with_stdio(0);
  cin.tie(0);
  int l, r;
  cin >> l >> r;
  if (r - l + 1 <= 2019) {
    int ans = 2018;
    for (int i = l; i <= r; i++) {
      for (int j = i + 1; j <= r; j++) {
        ans = min(ans, i * j % 2019);
      }
    }
    cout << ans << endl;
  } else {
    int ans = 2018;
    for (int i = l; i <= r; i += 2019 - l % 2019) {
      for (int j = i + 1; j <= r; j += 2019 - l % 2019) {
        ans = min(ans, i * j % 2019);
      }
    }
    cout << ans << endl;
  }
  return 0;
}
/* Think about this stuff:
   - printing: double -> int || printf
   - use for loop instead of memset
   - check bounds & edge cases
   - just implement something
   - find reason of tle
*/


Fixed submission:
// author: zekigurbuz
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef vector<bool> vb;
typedef vector<int> vi;
typedef vector<string> vs;
typedef vector<double> vd;
typedef vector<pii> vpii;
typedef queue<int> qi;
typedef map<string, int> msi;
#define RANGE_SUM 0
#define RANGE_MIN 1
#define RANGE_MAX 2
#define RANGE_XOR 3
#define RANGE_MUL 4
#define RANGE_OR 5
#define RANGE_AND 6
#define bit_ison(S, j) (S & (1 << j))
#define bit_setbit(S, j) (S |= (1 << j))
#define bit_clearbit(S, j) (S &= ~(1 << j))
#define bit_togglebit(S, j) (S ^= (1 << j))
#define bit_lowestbit(S) (S & (-S))
#define bit_setallon(S, n) (S = (1 << n) - 1)
#define bit_ispowertwo(S) (!(S & (S - 1))
#define bit_turnofflastbit(S) ((S) & (S - 1))
#define bit_turnonlastzero(S) ((S) | (S + 1))
#define int ll
#define double ld
#define M0D 1000000007
#define imin -(1e18)
#define imax 1e18
#define endl '\n'
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define forn(a, b) for (int a = 0; a < b; ++a)
#define rep(a, b, c) for (int a = b; a < c; ++a)
const ld PI = 4 * atan((ld)1);
vs split(string s) {
  vs v;
  istringstream iss(s);
  do {
    string sub;
    iss >> sub;
    v.pb(sub);
  } while (iss);
  v.pop_back();
  return v;
}
int gcd(int a, int b) { return a == 0 ? b : gcd(b % a, a); }
int lcm(int a, int b) { return a * b / gcd(a, b); }
int p0wm(int n, int p, int m) {
  if (p == 0)
    return 1;
  if (p == 1)
    return n % m;
  if (p % 2 == 0) {
    int t = p0wm(n, p / 2, m);
    return t % m * t % m % m;
  }
  int t = p0wm(n, p / 2, m);
  t = t % m * t % m % m;
  return t % m * n % m % m;
}
int p0w(int n, int p) {
  if (p == 0)
    return 1;
  if (p == 1)
    return n;
  if (p % 2 == 0) {
    int t = p0w(n, p / 2);
    return t * t;
  }
  int t = p0w(n, p / 2);
  return t * t * n;
}
int m0d(int n, int m) { return (m + (n % m)) % m; }
int fact(int n) {
  int a = 1;
  for (int i = 1; i <= n; ++i)
    a *= i;
  return a;
}
bool ip(int n) {
  if (n <= 1)
    return false;
  if (n == 2)
    return true;
  for (int i = 2; i * i <= n; ++i)
    if (n % i == 0)
      return false;
  return true;
}
vb ps(int n) {
  vector<bool> p;
  forn(i, n + 1) { p.pb(true); }
  p[0] = false;
  p[0] = p[1] = false;
  for (int i = 2; i * i <= n; ++i) {
    if (p[i]) {
      for (int j = i * i; j <= n; j += i) {
        p[j] = false;
      }
    }
  }
  return p;
}
vi psp(int n) {
  vector<bool> p = ps(n);
  vi a;
  forn(i, n + 1) if (p[i]) a.pb(i);
  return a;
}
// variables: vi pset, vi size, int numsets. methods: constructor(int n), int
// find_set(int i) void unify(int i, int j) bool same_set(int i, int j)
struct dsu {
  vi pset;
  vi size;
  int numsets;
  dsu(int n) {
    numsets = n;
    pset.resize(n);
    size.resize(n);
    forn(i, n) pset[i] = i;
    forn(i, n) size[i] = 1;
  }
  int find_set(int i) { return pset[i] == i ? i : pset[i] = find_set(pset[i]); }
  void unify(int i, int j) {
    int a = find_set(i), b = find_set(j);
    if (a == b)
      return;
    numsets--;
    if (size[a] < size[b]) {
      pset[a] = b;
      size[b] += size[a];
    } else {
      pset[b] = a;
      size[a] += size[b];
    }
  }
  bool same_set(int i, int j) { return find_set(i) == find_set(j); }
  int size_set(int i) { return size[find_set(i)]; }
};
// variables: vi bit, int size. methods: constructor(int n), int sum(int a), int
// sum(int a, int b), void update(int k, int x)
struct fenwick {
  vi bit;
  int size;
  fenwick(int n) {
    size = n;
    bit.resize(n + 1, 0);
  }
  int sum(int a) {
    int s = 0;
    while (a >= 1) {
      s += bit[a];
      a -= a & -a;
    }
    return s;
  }
  int sum(int a, int b) { return sum(b) - (a == 1 ? 0 : sum(a - 1)); }
  void update(int k, int x) {
    while (k <= size) {
      bit[k] += x;
      k += k & -k;
    }
  }
};
// variables: int code, int size, vi segment_tree. methods: constructor(int n,
// int type), void update(...), int query(...)
struct segtree {
  int code;
  int size;
  vi segment_tree;
  segtree(int n, int type) {
    n = (int)(2 * pow(2, floor(log2(n)) + 3));
    size = n;
    code = type;
    segment_tree.resize(n, 0);
  }
  void update(int index, int value) { update(1, 0, size - 1, index, value); }
  void update(int index, int left, int right, int i, int value) {
    if (left == right)
      segment_tree[index] = value;
    else {
      int mid = (left + right) / 2;
      if (i <= mid) {
        update(2 * index, left, mid, i, value);
      } else {
        update(2 * index + 1, mid + 1, right, i, value);
      }
      switch (code) {
      case RANGE_SUM:
        segment_tree[index] =
            segment_tree[2 * index] + segment_tree[2 * index + 1];
        break;
      case RANGE_MIN:
        segment_tree[index] =
            min(segment_tree[2 * index], segment_tree[2 * index + 1]);
        break;
      case RANGE_MAX:
        segment_tree[index] =
            max(segment_tree[2 * index], segment_tree[2 * index + 1]);
        break;
      case RANGE_XOR:
        segment_tree[index] =
            segment_tree[2 * index] ^ segment_tree[2 * index + 1];
        break;
      case RANGE_MUL:
        segment_tree[index] =
            segment_tree[2 * index] * segment_tree[2 * index + 1];
        break;
      case RANGE_OR:
        segment_tree[index] =
            segment_tree[2 * index] | segment_tree[2 * index + 1];
        break;
      case RANGE_AND:
        segment_tree[index] =
            segment_tree[2 * index] & segment_tree[2 * index + 1];
        break;
      }
    }
  }
  int query(int left, int right) { return query(1, 0, size - 1, left, right); }
  int query(int index, int left, int right, int lhs, int rhs) {
    if (left >= lhs && right <= rhs) {
      return segment_tree[index];
    } else {
      int ret = 0;
      switch (code) {
      case RANGE_SUM:
        ret = 0;
        break;
      case RANGE_MIN:
        ret = imax;
        break;
      case RANGE_MAX:
        ret = imin;
        break;
      case RANGE_XOR:
        ret = 0;
        break;
      case RANGE_MUL:
        ret = 1;
        break;
      case RANGE_OR:
        ret = 0;
        break;
      case RANGE_AND:
        ret = 9223372036854775807;
        break;
      }
      int mid = (left + right) / 2;
      if (mid >= lhs) {
        switch (code) {
        case RANGE_SUM:
          ret += query(2 * index, left, mid, lhs, rhs);
          break;
        case RANGE_MIN:
          ret = min(ret, query(2 * index, left, mid, lhs, rhs));
          break;
        case RANGE_MAX:
          ret = max(ret, query(2 * index, left, mid, lhs, rhs));
          break;
        case RANGE_XOR:
          ret ^= query(2 * index, left, mid, lhs, rhs);
          break;
        case RANGE_MUL:
          ret *= query(2 * index, left, mid, lhs, rhs);
          break;
        case RANGE_OR:
          ret |= query(2 * index, left, mid, lhs, rhs);
          break;
        case RANGE_AND:
          ret &= query(2 * index, left, mid, lhs, rhs);
          break;
        }
      }
      if (mid + 1 <= rhs) {
        switch (code) {
        case RANGE_SUM:
          ret += query(2 * index + 1, mid + 1, right, lhs, rhs);
          break;
        case RANGE_MIN:
          ret = min(ret, query(2 * index + 1, mid + 1, right, lhs, rhs));
          break;
        case RANGE_MAX:
          ret = max(ret, query(2 * index + 1, mid + 1, right, lhs, rhs));
          break;
        case RANGE_XOR:
          ret ^= query(2 * index + 1, mid + 1, right, lhs, rhs);
          break;
        case RANGE_MUL:
          ret *= query(2 * index + 1, mid + 1, right, lhs, rhs);
          break;
        case RANGE_OR:
          ret |= query(2 * index + 1, mid + 1, right, lhs, rhs);
          break;
        case RANGE_AND:
          ret &= query(2 * index + 1, mid + 1, right, lhs, rhs);
          break;
        }
      }
      return ret;
    }
  }
};

signed main() {
  ios_base::sync_with_stdio(0);
  cin.tie(0);
  int l, r;
  cin >> l >> r;
  if (r - l + 1 <= 2019) {
    int ans = 2018;
    for (int i = l; i <= r; i++) {
      for (int j = i + 1; j <= r; j++) {
        ans = min(ans, i * j % 2019);
      }
    }
    cout << ans << endl;
  } else {
    int ans = 2018;
    for (int i = l; i <= r; i += 2019 - l % 2019) {
      ans = min(ans, min(i * (i + 1) % 2019,
                         i * (i + 1 + 2019 - (i + 1) % 2019) % 2019));
    }
    cout << ans << endl;
  }
  return 0;
}
/* Think about this stuff:
   - printing: double -> int || printf
   - use for loop instead of memset
   - check bounds & edge cases
   - just implement something
   - find reason of tle
*/